LoginSignup
91
97

More than 5 years have passed since last update.

ECMAScript6の新機能

Last updated at Posted at 2017-06-12

以下はGithubで2万☆を獲得している、Overview of ECMAScript 6 featuresというコンテンツの日本語訳です。

Introduction

ECMAScript2015とも言われているECMAScript6は、ECMAScript標準の最新バージョンです。
ES6は、2009年に標準化されたES5以来、初めての重要なアップデートになります。
主要なJavaScriptエンジンにおいて、現在これら新機能の実装が進行中です。

ES6の完全な仕様については、ES6 standardを参照してください。
ES6には、以下のような新機能が含まれています。

ECMAScript 6 Features

arrows

アロー=>は、functionの省略表記で、C#、Java8やCoffeeScriptのアローと似たような構文で書けるよ。
式と文どちらの書き方もサポートするよ。
呼び出し方でthisが変わるfunctionとは違い、アローのthisは常にその周囲と同じスコープになるよ。

    // 式
    var odds = evens.map(v => v + 1);
    var nums = evens.map((v, i) => v + i);
    var pairs = evens.map(v => ({even: v, odd: v + 1}));

    // 文
    nums.forEach(v => {
      if (v % 5 === 0)
        fives.push(v);
    });

    // thisのスコープ
    var bob = {
      _name: "Bob",
      _friends: [],
      printFriends() {
        this._friends.forEach(f =>
          console.log(this._name + " knows " + f));
      }
    }

より詳細はMDN Arrow Functionsを参照すること。

classes

ES6のクラス構文は、プロトタイプベース言語をオブジェクト指向に見せかけるシンタックスシュガーです。
ひとつ便利な定義を追加することで、クラス構文が使いやすくなり相互運用性も高まります。
クラスは継承、super、インスタンスメソッドとクラスメソッド、コンストラクタをサポートします。

    class SkinnedMesh extends THREE.Mesh {

      // コンストラクタ
      constructor(geometry, materials) {
        // super.constructor()
        super(geometry, materials);

        this.idMatrix = SkinnedMesh.defaultMatrix();
        this.bones = [];
        this.boneMatrices = [];
        //...
      }
      // インスタンスメソッド
      update(camera) {
        //...
        super.update();
      }
      // getter
      get boneCount() {
        return this.bones.length;
      }
      //setter
      set matrixType(matrixType) {
        this.idMatrix = SkinnedMesh[matrixType]();
      }
      // クラスメソッド
      static defaultMatrix() {
        return new THREE.Matrix4();
      }
    }

より詳細はMDN Classesを参照すること。

enhanced object literals

オブジェクトリテラルはfoo:fooの省略、メソッド定義、super()、プロパティ名の演算などに対応しました。
オブジェクトリテラルとクラス構文を一緒に利用することで、これらがより便利に扱えるようになります。

var obj = {
    // __proto__
    __proto__: theProtoObj,
    // handler: handlerの略
    handler,
    // メソッド
    toString() {
      // theProtoObj.toString()を呼んでる
      return "d " + super.toString();
    },
    // 計算結果をプロパティ名にできる
    [ 'prop_' + (() => 42)() ]: 42
};

より詳細はMDN Grammar and types: Object literalsを参照すること。

template strings

テンプレートリテラルは文字列を作成するためのシンタックスシュガーです。
これはPerlやPythonなどのヒアドキュメントと似ています。
オプションで、タグを付けることで文字列作成をカスタマイズすることができます。
インジェクション攻撃を防いだり、より高度な文字列作成ができるでしょう。

    // 基本
    `In JavaScript '\n' is a line-feed.`

    // 複数行
    `In JavaScript this is
     not legal.`

    // 文字列展開
    var name = "Bob", time = "today";
    `Hello ${name}, how are you ${time}?`

    // POST関数が呼ばれる
    POST`http://foo.org/bar?a=${a}&b=${b}
         Content-Type: application/json
         X-Credentials: ${credentials}
         { "foo": ${foo},
           "bar": ${bar}}`(myOnReadyStateChangeHandler);

より詳細はMDN Template Stringsを参照すること。

destructuring

分割代入は配列とオブジェクトによるバインディングをサポートしています。
分割代入はfoo["bar"]の参照と同じようにフェールセーフで、値がなかったらundefinedを返します。

    // 配列
    var [a, , b] = [1,2,3];

    // オブジェクト
    var { op: a, lhs: { op: b }, rhs: c }
           = getASTNode()

    // オブジェクトの短縮形
    var {op, lhs, rhs} = getASTNode()

    // 引数
    function g({name: x}) {
      console.log(x);
    }
    g({name: 5})

    // フェールソフト
    var [a] = []; // a === undefined

    // デフォルト値があればそっちになる
    var [a = 1] = []; // a === 1

より詳細はMDN Destructuring assignmentを参照すること。

default + rest + spread

関数呼び出し時に引数が無かった場合はデフォルト値が使用される。。
呼び出される方に書く...はRest parametersと呼ばれ、余った引数が全て配列で入ってくる。
呼び出す方に書く...はスプレッド演算子と呼ばれ、配列を展開して呼び出し先に渡される。

    function f(x, y=12) {
      // 第二引数が無いかundefinedのときはy=12になる
      return x + y;
    }
    f(3) // 15

    function f(x, ...y) {
      // y = ["hello", true]になる
      return x * y.length;
    }
    f(3, "hello", true) // 6

    function f(x, y, z) {
      return x + y + z;
    }
    // f(1, 2, 3)と同じ
    f(...[1, 2, 3]) // 6

より詳細はMDN Default parametersRest parametersSpread Operatorを参照すること。

let + const

letはブロックスコープのvarで再代入可能。
constは再代入不可能。

    function f() {
      {
        let x;

        {
          // {}内のスコープになるので定義可能
          const x = "sneaky";
          // constは再代入不可なのでエラーになる
          x = "foo";
        }

        // 同スコープで既にletしてるのでエラーになる
        let x = "inner";
        // 再代入はOK
        x = "inner";
      }
    }

より詳細はMDN let statementconst statementを参照すること。

iterators + for..of

イテレータはIEnumerableIterableのように反復処理をカスタマイズできます。
for-ofを使うと、for-inより簡単にイテレータから値を取り出せます。
特に何もしなくてもLINQのように遅延評価されます。

    let fibonacci = {
      [Symbol.iterator]() {
        let pre = 0, cur = 1;
        return {
          next() {
            [pre, cur] = [cur, pre + cur];
            return { done: false, value: cur }
          }
        }
      }
    }

    for (var n of fibonacci) {
      // 1000で終了
      if (n > 1000)
        break;
      console.log(n);
    }

イテレータのinterfaceをTypeScriptで書くと以下のようになります。

    interface IteratorResult {
      done: boolean;
      value: any;
    }
    interface Iterator {
      next(): IteratorResult;
    }
    interface Iterable {
      [Symbol.iterator](): Iterator
    }

より詳細はMDN for...ofを参照すること。

generators

ジェネレータは、function*yieldを使ってイテレータを簡単に作れる機能です。
function*で宣言した関数はGeneratorインスタンスを返します。
ジェネレータはnextthrowを持ったイテレータのサブタイプで、yieldで関数は動いたまま値を返します(もしくはthrowする)。

注:イテレータを使うとES7のawaitみたいなこともできるよ

    var fibonacci = {
      [Symbol.iterator]: function*() {
        var pre = 0, cur = 1;
        for (;;) {
          var temp = pre;
          pre = cur;
          cur += temp;
          yield cur;
        }
      }
    }

    for (var n of fibonacci) {
      // 1000で終了
      if (n > 1000)
        break;
      console.log(n);
    }

ジェネレータのinterfaceをTypeScriptで書くと以下のようになります。

    interface Generator extends Iterator {
        next(value?: any): IteratorResult;
        throw(exception: any);
    }

より詳細はMDN Iteration protocolsを参照すること。

unicode

ユニコードリテラル、RegExpのUnicodeフラグ、21ビットのコードポイントAPIなど、Unicodeサポートを強化しました。
これらにより、JavaScriptでグローバルなアプリ作成が容易になります。

    // これまでと同じ
    "𠮷".length == 2

    // Unicodeフラグ
    "𠮷".match(/./u)[0].length == 2

    // Unicodeリテラル
    "\u{20BB7}"=="𠮷"=="\uD842\uDFB7"

    // String.prototype.codePointAt()
    "𠮷".codePointAt(0) == 0x20BB7

    // イテレータ
    for(var c of "𠮷") {
      console.log(c);
    }

より詳細はMDN RegExp.prototype.unicodeを参照すること。

modules

コンポーネント定義のモジュールを言語レベルでサポートしました。
一般的なAMDCommonJSみたいな形で書けます。
モジュールは非同期で、必要とされるまで中のコードは実行されません。

    // lib/math.js
    export function sum(x, y) {
      return x + y;
    }
    export var pi = 3.141593;

    // app.js
    import * as math from "lib/math";
    alert("2π = " + math.sum(math.pi, math.pi));

    // otherApp.js
    import {sum, pi} from "lib/math";
    alert("2π = " + sum(pi, pi));

追加機能としては、export defaultexport *があります。

    // lib/mathplusplus.js
    export * from "lib/math";
    export var e = 2.71828182846;
    export default function(x) {
        return Math.log(x);
    }

    // app.js
    import ln, {pi, e} from "lib/mathplusplus";
    alert("2π = " + ln(e)*pi*2);

より詳細はMDN import statementexport statementを参照すること。

module loaders

モジュールローダは以下をサポートします。
・動的ローディング
・状態の分離
・グローバル領域を使わない
・コンパイル時フック
・仮想化のネスト

デフォルトのローダを変更することができ、また新しいローダを作成することもできます。

    // 動的ローディング 'System'はデフォルトのローダ
    System.import('lib/math').then(function(m) {
      alert("2π = " + m.sum(m.pi, m.pi));
    });

    // 新しいローダ
    var loader = new Loader({
      global: fixup(window) // 'console.log'を差し替える
    });
    loader.eval("console.log('hello world!');");

    // モジュールを直接操作
    System.get('jquery');
    System.set('jquery', Module({$: $})); // WARNING: not yet finalized

map + set + weakmap + weakset

一般的なアルゴリズムに対して効率的なデータ構造。
WeakMapはメモリリークのない、オブジェクトをキーとするKey-Valueストアです。

    // Set
    var s = new Set();
    s.add("hello").add("goodbye").add("hello");
    s.size === 2;
    s.has("hello") === true;

    // Map
    var m = new Map();
    m.set("hello", 42);
    m.set(s, 34);
    m.get(s) == 34;

    // WeakMap
    var wm = new WeakMap();
    wm.set(s, { extra: 42 });
    wm.size === undefined

    // WeakSet
    var ws = new WeakSet();
    ws.add({ data: 42 });
    // Weak*以外から参照がない場合、キーはGCされる

より詳細はMDN MapSetWeakMapWeakSetを参照すること。

proxies

Proxyを使うと、おおよそあらゆるオブジェクトを上書きして挙動を変更することが可能になります。
傍受、オブジェクトの仮想化、ロギングなどに使用できるでしょう。

    // 普通のObject
    var target = {};
    var handler = {
      get: function (receiver, name) {
        return `Hello, ${name}!`;
      }
    };

    // targetをhandlerで上書き
    var p = new Proxy(target, handler);
    p.world === 'Hello, world!';

    // 普通の関数
    var target = function () { return 'I am the target'; };
    var handler = {
      apply: function (receiver, ...args) {
        return 'I am the proxy';
      }
    };

    // targetをhandlerで上書き
    var p = new Proxy(target, handler);
    p() === 'I am the proxy';

ランタイムレベルの操作も上書きできます。

    var handler =
    {
      get:...,
      set:...,
      has:...,
      deleteProperty:...,
      apply:...,
      construct:...,
      getOwnPropertyDescriptor:...,
      defineProperty:...,
      getPrototypeOf:...,
      setPrototypeOf:...,
      enumerate:...,
      ownKeys:...,
      preventExtensions:...,
      isExtensible:...
    }

より詳細はMDN Proxyを参照すること。

symbols

SymbolはObjectに対するアクセス制御を可能にします。
SymbolはObjectのキーとして設定できる、新しいプリミティブ型です。
引数descriptionを渡せますが、必須ではありません。
Symbolはgensymのように一意ですが、Object.getOwnPropertySymbolsで列挙できるのでprivateではありません。

    var MyClass = (function() {

      // Symbol
      var key = Symbol("key");

      // キーにする
      function MyClass(privateData) {
        this[key] = privateData;
      }

      MyClass.prototype = {
        doStuff: function() {
          ... this[key] ...
        }
      };

      return MyClass;
    })();

    var c = new MyClass("hello");
    // MyClass.keyとは別物なので参照不可
    c["key"] === undefined;

より詳細はMDN Symbolを参照すること。

subclassable built-ins

ES6ではArray、Date、DOM Elementsのような組み込み関数を継承できます。
オブジェクト生成時にCtorという関数が呼ばれ、以下の処理を行います。
Ctor[@@create]を呼んでオブジェクトを生成する
constructorを呼んでインスタンスを生成する

Symbol.createで既知の@@createを利用できます。
組み込み関数は@@createを公開しています。

    // Arrayの擬似コード
    class Array {
        constructor(...args) { /* ... */ }
        static [Symbol.create]() {
            // Install special [[DefineOwnProperty]] to magically update 'length'
        }
    }

    // Arrayのサブクラス
    class MyArray extends Array {
        constructor(...args) { super(...args); }
    }

    // newすると`@@create`、`constructor`を順に呼び出す
    var arr = new MyArray();
    arr[1] = 12;
    arr.length == 2

math + number + string + array + object APIs

Mathライブラリ、配列変換、文字列操作、Object.assignなど多くのライブラリが追加されました。

    Number.EPSILON;
    Number.isInteger(Infinity); // false
    Number.isNaN("NaN"); // false

    Math.acosh(3); // 1.762747174039086
    Math.hypot(3, 4); // 5
    Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2); // 2

    "abcde".includes("cd"); // true
    "abc".repeat(3); // "abcabcabc"

    Array.from(document.querySelectorAll('*')); // Arrayを返す
    Array.of(1, 2, 3); // new Array()とほぼ同じだが、引数が一つのときに動作が変わらない
    [0, 0, 0].fill(7, 1); // [0,7,7]
    [1, 2, 3].find(x => x == 3); // 3
    [1, 2, 3].findIndex(x => x == 2); // 1
    [1, 2, 3, 4, 5].copyWithin(3, 0); // [1, 2, 3, 1, 2]
    ["a", "b", "c"].entries(); // [0, "a"], [1,"b"], [2,"c"]のイテレータ
    ["a", "b", "c"].keys(); // 0, 1, 2のイテレータ
    ["a", "b", "c"].values(); // "a", "b", "c"のイテレータ

    Object.assign(Point, { origin: new Point(0,0) })

より詳細はMDN NumberMathArray.fromArray.ofArray.prototype.copyWithinObject.assignを参照すること。

binary and octal literals

数値リテラルに2進数表記bと8進数表記oが追加されました。

    0b111110111 === 503 // true
    0o767 === 503 // true

promises

Promiseは非同期処理を行う第一級関数ライブラリです。
Promiseは既に多くのJavaScriptライブラリで使用されています。

    function timeout(duration = 0) {
        return new Promise((resolve, reject) => {
            setTimeout(resolve, duration);
        })
    }

    var p = timeout(1000).then(() => {
        return timeout(2000);
    }).then(() => {
        throw new Error("hmm");
    }).catch(err => {
        return Promise.all([timeout(100), timeout(200)]);
    })

より詳細はMDN Promiseを参照すること。

reflect api

リフレクションAPIはObjectに対するメタ操作を可能とします。
これはProxy APIの逆みたいなもので、Proxy同様呼び出しをフックできます。
Proxyの実装に特に便利です。

    // サンプルはないよ

より詳細はMDN Reflectを参照すること。

tail calls

末尾再帰を最適化します。
再帰的なアルゴリズムに無限の入力があっても今後は安心です。

    function factorial(n, acc = 1) {
        'use strict';
        if (n <= 1) return acc;
        return factorial(n - 1, n * acc);
    }

    // 今はStack overflowが起こるけど、ES6では安全になる
    factorial(100000)

感想

PHP5.0からPHP5.3に進化したみたいなかんじ?

正直ES6よくわかってないので、読んでもわからないところが多かった。
というかこのGithub全体的にあまりに端折りすぎてて、詳細を見ない限り機能が存在することくらいしかわからない。
さらに更新が一年前から止まっていて、大量のプルリクも放置状態。
どうして2万も☆がついてるのかよくわからない。

あとCtor[@@create]が何なのか全くわからなかった。

91
97
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
91
97