(1)

ECMAScript 6 Features

2015/06/06
2015/06/30 改訂
taskie

(2)

このスライドについて


(3)

TL;DR(抜粋)


(4)

目次


(5)

最適化 (Optimization)


(6)

末尾呼び出し最適化

ES6

function gcd(m, n) {
    if (n === 0) {
        return m;
    } else {
        return gcd(n, m % n);
    }
}

(7)

文法 (Syntax)


(8)

デフォルト引数

ES3

function myPow(x, y) {
    if (typeof y === "undefined") y = 2;
    return Math.pow(x, y);
}
console.log(myPow(3));      // 9
console.log(myPow(2, 10));  // 1024

(9)

デフォルト引数

ES5

function myPow(x, y) {
    if (y === undefined) y = 2;
    return Math.pow(x, y);
}
console.log(myPow(3));      // 9
console.log(myPow(2, 10));  // 1024

(10)

デフォルト引数

ES6

function myPow(x, y = 2) {

    return Math.pow(x, y);
}
console.log(myPow(3));      // 9
console.log(myPow(2, 10));  // 1024

(11)

可変長引数

ES3 / ES5

function f(x) {
    console.log(x, Array.prototype.slice.call(arguments, 1));
}
f(2, 3, 5);  // 2 [ 3, 5 ]

(12)

可変長引数

ES6

function f(x, ...ys) {
    console.log(x, ys);
}
f(2, 3, 5);  // 2 [ 3, 5 ]

(13)

配列の展開(引数編)

ES3 / ES5

function f(x, y, z) {
    console.log(x + y * z);
}
f.apply(null, [2, 3, 5]);  // 17

(14)

配列の展開(引数編)

ES6

function f(x, y, z) {
    console.log(x + y * z);
}
f(...[2, 3, 5]);           // 17

(15)

配列の展開(配列リテラル編)

ES3 / ES5

var xs = [5, 7];
var ys = [2, 3].concat(xs, [11, 13])
console.log(ys);  // [ 2, 3, 5, 7, 11, 13 ]

(16)

配列の展開(配列リテラル編)

ES6

var xs = [5, 7];
var ys = [2, 3, ...xs, 11, 13];
console.log(ys);  // [ 2, 3, 5, 7, 11, 13 ]

(17)

式をプロパティ名に使う

ES3 / ES5

var key = "foo";
var obj = {};
obj[key] = "bar";
console.log(obj); // { "foo" : "bar" }

(18)

式をプロパティ名に使う

ES6

var key = "foo";
var obj = {[key]: "bar"};

console.log(obj); // { "foo" : "bar" }

(19)

プロパティ名の略記

ES3 / ES5

var x = 2, y = 3, z = 5;
var obj = {x: x, y: y, z: z};

(20)

プロパティ名の略記

ES6

var x = 2, y = 3, z = 5;
var obj = {x, y, z};

(21)

メソッドの略記

ES3 / ES5

var obj = {
    f: function (x) {
        console.log(x * this.y);
    },
    y: 42
};

(22)

メソッドの略記

ES6

var obj = {
    f(x) {
        console.log(x * this.y);
    },
    y: 42
};

(23)

列挙 (forof)

ES3 (BAD)

var xs = [2, 3, 5];
for (var i in xs) {
    console.log(xs[i]);
}

(24)

列挙 (forof)

ES3 (GOOD)

var xs = [2, 3, 5];
for (var i = 0; i < xs.length; ++i) {
    console.log(xs[i]);
}

(25)

列挙 (forof)

ES5

var xs = [2, 3, 5];
xs.forEach(function (x, i) {
    console.log(x);
});

(26)

列挙 (forof)

ES6

var xs = [2, 3, 5];
for (var x of xs) {
    console.log(x);
}

(27)

2進数 / 8進数リテラル

ES6

console.log(0b1010);  // 10
console.log(0o755);   // 493

(28)

テンプレートリテラル

ES3 / ES5

var a = 7, b = 8;
console.log(a + " + " + b + " = " + (a + b));

(29)

テンプレートリテラル

ES6

var a = 7, b = 8;
console.log(`${a} + ${b} = ${a + b}`);

(30)

新しい正規表現のフラグ (y, u)

ES6

var re = /(\d+)\.?/y;
var ip = "127.0.0.1";
while (re.exec(ip)) console.log(re.lastIndex);  // 4 6 8 9
console.log(/🍣🍺*🍖/.test("🍣🍺🍺🍺🍖"));  // false
console.log(/🍣🍺*🍖/u.test("🍣🍺🍺🍺🍖")); // true

(31)

分割代入

ES3 / ES5

var xs = [2, 3, 5];
var x = xs[0], y = xs[1], z = xs[2];
var obj = {x: 2, y: 3, nested: {z: 5}};
var x = obj.x, y = obj.y, z = obj.nested.z;
var obj = {x: 2, y: 3, nested: {z: 5}};
var a = obj.x, b = obj.y, c = obj.nested.z;

(32)

分割代入

ES6

var xs = [2, 3, 5];
var [x, y, z] = xs;
var obj = {x: 2, y: 3, nested: {z: 5}};
var {x, y, nested: {z}} = obj;
var obj = {x: 2, y: 3, nested: {z: 5}};
var {x: a, y: b, nested: {z: c}} = obj;

(33)

束縛 (Bindings)


(34)

ブロックスコープ変数 (let)

ES3 / ES5 (BAD)

var s = "foo";
{
    var s = "bar";
    console.log(s);  // bar
}
console.log(s);  // bar

(35)

ブロックスコープ変数 (let)

ES3 / ES5 (GOOD)

var s = "foo";
(function () {
    var s = "bar";
    console.log(s);  // bar
})();
console.log(s);  // foo

(36)

ブロックスコープ変数 (let)

ES6

var s = "foo";
{
    let s = "bar";
    console.log(s);  // bar
}
console.log(s);  // foo

(37)

letfor

ES3 / ES5 (BAD)

var fs = [];
for (var i = 0; i < 3; ++i) {
    var f = function () {
        console.log(i);
    };
    fs.push(f);
}
for (var i = 0; i < 3; ++i) {
    fs[i]();  // 3, 3, 3
}

(38)

letfor

ES3 / ES5 (GOOD)

var fs = [];
for (var i = 0; i < 3; ++i) {
    var f = (function (i) {
        return function () { console.log(i); };
    })(i);
    fs.push(f);
}
for (var i = 0; i < 3; ++i) {
    fs[i]();  // 0, 1, 2
}

(39)

letfor

ES6

var fs = [];
for (let i = 0; i < 3; ++i) {
    var f = function () {
        console.log(i);
    };
    fs.push(f);
}
for (var i = 0; i < 3; ++i) {
    fs[i]();  // 0, 1, 2
}

(40)

定数 (const)

ES6

const answer = 42;
answer = 0;  // compile error
const s = "foo";
{
    const s = "bar";
    console.log(s);  // bar
}
console.log(s);  // foo

(41)

関数 (Functions)


(42)

アロー関数

ES3 / ES5

var myRandom = function (x, y) {
    var range = y - x;
    return x + (Math.random() * range);
};
var pow2 = function (x) { return x * x };

(43)

アロー関数

ES6

var myRandom = (x, y) => {
    var range = y - x;
    return x + (Math.random() * range);
};
var pow2 = x => x * x;

(44)

アロー関数(this の扱い)

ES3 / ES5 (BAD)

var obj = {
    f: function () {

        setTimeout(function () {
            console.log(this.x);
        }, 1000);
    },
    x: 42
};
obj.f();  // undefined

(45)

アロー関数(this の扱い)

ES3 (GOOD)

var obj = {
    f: function () {
        var that = this;
        setTimeout(function () {
            console.log(that.x);
        }, 1000);
    },
    x: 42
};
obj.f();  // 42

(46)

アロー関数(this の扱い)

ES5 (GOOD)

var obj = {
    f: function () {

        setTimeout((function () {
            console.log(this.x);
        }).bind(this), 1000);
    },
    x: 42
};
obj.f();  // 42

(47)

アロー関数(this の扱い)

ES6

var obj = {
    f: function () {

        setTimeout(() => {
            console.log(this.x);
        }, 1000);
    },
    x: 42
};
obj.f();  // 42

(48)

クラス (class)

ES3 / ES5


(49)

クラス (class)

ES6

class Application {
    constructor(name) {
        this.name = name;
    }
    start() {
        document.addEventListener("DOMContentLoaded", (event) => {
            this.domDidLoad(event);
        });
    }
    domDidLoad(event) {
        console.log(event);
        console.log(this);
        console.log(`Application ${this.name} start...`);
    }
}

(50)

クラスの継承 (extends, super)

ES6

class MyApplication extends Application {
    constructor(name, canvasId, fps = 60) {
        super(name);
        this.canvasId = canvasId;
        this.fps = fps;
    }
    domDidLoad(event) {
        super.domDidLoad(event);
        this.canvas = document.getElementById(this.canvasId);
        this.context = this.canvas.getContext("2d");
        setTimeout(() => this.draw(this.context), 1000 / this.fps);
    }
    draw(ctx) {
        ctx.fillStyle = "#def";
        ctx.fillRect(0, 0, 640, 480);
    }
}

(51)

クラス(this の扱い)

ES6 (GOOD)

document.addEventListener("DOMContentLoaded", (event) => {
    this.domDidLoad(event);
});
setTimeout(() => this.draw(this.context), 1000 / this.fps);

(52)

クラス(this の扱い)

ES6 (BAD)

document.addEventListener("DOMContentLoaded", function (event) {
    this.domDidLoad(event);
});
setTimeout(function () { this.draw(this.context); }, 1000 / this.fps);

(53)

クラス(this の扱い)

ES6 (BAD)

document.addEventListener("DOMContentLoaded", this.domDidLoad);

(54)

クラス(this の扱い)

ES6 (GOOD) (2)

document.addEventListener("DOMContentLoaded", this.domDidLoad.bind(this));
setTimeout(this.draw.bind(this, this.context), 1000 / this.fps);

(55)

ジェネレータ

ES6

function * range(n) {
    for (var i = 0; i < n; ++i) yield i;
}

const gen = range(3);
console.log(gen.next());  // { value: 0, done: false }
console.log(gen.next());  // { value: 1, done: false }
console.log(gen.next());  // { value: 2, done: false }
console.log(gen.next());  // { value: undefined, done: true }

(56)

ジェネレータの列挙

ES6

function * range(n) {
    for (var i = 0; i < n; ++i) yield i;
}

for (var i of range(3)) {
    console.log(i);  // 0, 1, 2
}

(57)

ジェネレータの展開

ES6

function * range(n) {
    for (var i = 0; i < n; ++i) yield i;
}

console.log([...range(2), ...range(3)]);  // [ 0, 1, 0, 1, 2 ]

(58)

ビルトイン (Built-ins)


(59)

型付き配列

ES6

var xs = new Float32Array(3);
console.log(xs);  // [ 0, 0, 0 ]
var ys = new Uint8Array([-1, 0, 255, 256]);
console.log(ys);  // [ 255, 0, 255, 0 ]
var zs = new Uint8ClampedArray([-1, 0, 255, 256]);
console.log(zs);  // [ 0, 0, 255, 255 ]

(60)

ArrayBuffer と型付き配列

ES6

var buf = new ArrayBuffer(8);
var f64 = new Float64Array(buf);
var i32 = new Int32Array(buf);
var ui8 = new Uint8Array(buf);
f64[0] = 0.1;
console.log(f64);  // [0.1]
console.log(i32);  // [-1717986918, 1069128089]
console.log(ui8);  // [154, 153, 153, 153, 153, 153, 185, 63]

(61)

DataView

ES6

var buf = new ArrayBuffer(4);
var view = new DataView(buf);
view.setUint8(0, 0xA0);
console.log(view.getInt32(0));        // -1610612736
console.log(view.getInt32(0, true));  // 160

(62)

Map

ES6

var map = new Map();
var key1 = {};
var key2 = {};
var key3 = key1;
map.set(key1, "foo");
map.set(key2, "bar");
console.log(map.get(key2));  // bar
console.log(map.get(key3));  // foo
for (var key of map.keys()) console.log(key);  // {} {}

(63)

WeakMap

ES6

var map = new WeakMap();
var key1 = {};
var key2 = {};
var key3 = key1;
map.set(key1, "foo");
map.set(key2, "bar");
console.log(map.get(key2));  // bar
console.log(map.get(key3));  // foo
console.log(typeof map.keys === "undefined");  // true

(64)

Set

ES6

var set = new Set([1, 1, 2, 3, 5, 8]);
set.add(2).add(3).add(5).add(7).add(11);
console.log(set);  // [ 1, 2, 3, 5, 8, 7, 11 ]
console.log(set.has(4));  // false
console.log(set.has(5));  // true

(65)

WeakSet

ES6

var set = new WeakSet();
var key1 = {};
var key2 = {};
var key3 = key1;
set.add(key1);
console.log(set.has(key2));  // false
console.log(set.has(key3));  // true

(66)

Proxy

ES6

var obj = {};
var handler = {
    get(target, name) { return target[name] / 2; },
    set(target, name, val) { target[name] = val * 2; }
};
var proxy1 = new Proxy(obj, handler);
var proxy2 = new Proxy(proxy1, handler);
var proxy3 = new Proxy(proxy2, handler);
proxy3.foo = 42;
console.log(proxy3.foo);  // 42
console.log(proxy2.foo);  // 84
console.log(proxy1.foo);  // 168
console.log(obj);  // { "foo" : 336 }

(67)

Reflect

ES6

var obj = {};
var handler = {
    get(target, name) { return Reflect.get(target, name) / 2; },
    set(target, name, val) { Reflect.set(target, name, val * 2); }
};
var proxy1 = new Proxy(obj, handler);
var proxy2 = new Proxy(proxy1, handler);
var proxy3 = new Proxy(proxy2, handler);
proxy3.foo = 42;
console.log(proxy3.foo);  // 42
console.log(proxy2.foo);  // 42
console.log(proxy1.foo);  // 42
console.log(obj);  // { "foo" : 84 }

(68)

Promise

ES6


(69)

Promise

ES6

new Promise((resolve, reject) => {
    setTimeout(() => resolve("A"), 1000);
}).then((str) => {
    console.log(str);          // A
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve("B"), 1000);
    }).then((str) => {
        console.log(str);      // B
        return Promise.reject(new Error("C"));
    });
}).catch((err) => {
    console.log(err.message);  // C
    return "D";
}).then((str) => {
    console.log(str);          // D
});
console.log("Start!");

(70)

Symbol

ES6

var sym1 = Symbol("foo");
var sym2 = Symbol("bar");
var sym3 = Symbol("bar");

console.log(sym1 == sym2);  // false
console.log(sym2 == sym3);  // false
console.log(sym3 == sym1);  // false

(71)

Symbol.iterator

ES6

var obj = { };
obj[Symbol.iterator] = function () {
    return {
        next: function () {
            return (this.i < 3) ?
                {done: false, value: this.i++} : {done: true};
        },
        i: 0
    }
};
for (var x of obj) console.log(x);  // 0 1 2

(72)

ビルトイン拡張 (Built-in extensions)


(73)

Object.assign

ES6

var obj = {foo: "bar", x: 42};
Object.assign(obj, {foo: "baz"}, {hoge: "piyo"});
console.log(obj);  // { "foo" : "baz", "x" : 42 , "hoge" : "piyo" }

(74)

Object.setPrototypeOf

ES6

var proto = {hoge: "piyo"};
var obj = {foo: "bar"};
Object.setPrototypeOf(obj, proto);
console.log(Object.getPrototypeOf(obj) === proto);  // true
console.log(obj.foo);   // bar
console.log(obj.hoge);  // piyo
obj.hoge = "fuga";
console.log(obj.hoge);  // fuga

(75)

関数名の取得

ES6

function foo() { }
console.log(foo.name);  // foo
var bar = function () { };
console.log(bar.name);  // bar
console.log((function () { }).name === "")  // true

(76)

String

ES6

console.log("🍣".codePointAt(0));  // 127843
console.log(String.fromCodePoint(12354, 32, 127843)); // あ 🍣
console.log("A".repeat(3));  // AAA
console.log("heart".includes("ear"));       // true
console.log("heart".startsWith("hear"));    // true
console.log("heart".startsWith("ear", 1));  // true
console.log("heart".endsWith("art"));       // true

(77)

Array

ES6

var obj = {0: "foo", 1: "bar", length: 2};
console.log(Array.from(obj));  // ["foo", "bar"]
function * gen() { yield 2; yield 3; yield 5; }
console.log(Array.from(gen()));  // [2, 3, 5]
console.log([2, 3, 5, 7].find(x => x > 3));       // 5
console.log([2, 3, 5, 7].findIndex(x => x > 3));  // 2
console.log(new Array(3).fill(42));  // [42, 42, 42]

(78)

Number

ES6

console.log(Number.isFinite(42));         // true
console.log(Number.isFinite(-Infinity));  // false
console.log(Number.isFinite(NaN));        // false
console.log(Number.isInteger(42.00000));  // true
console.log(Number.isInteger(42.00001));  // false
console.log(Number.isSafeInteger(1e+15)); // true
console.log(Number.isSafeInteger(1e+16)); // false
console.log(Number.EPSILON);              // 2.220446049250313e-16
console.log(Number.MIN_SAFE_INTEGER);            // -9007199254740991
console.log((Number.MIN_SAFE_INTEGER - 1) | 0);  // 0
console.log(Number.MAX_SAFE_INTEGER);            // 9007199254740991
console.log((Number.MAX_SAFE_INTEGER + 1) | 0);  // 0

(79)

Math

ES6

console.log(Math.sign(-42));          // -1
console.log(Math.cosh(Math.log(2)));  // 1.25
console.log(Math.trunc(-3.5));        // -3
console.log(Math.cbrt(27));           // 3
console.log(Math.hypot(3, 4));        // 5

(80)

サブクラス化 (Subclassing)


(81)

モジュール (Modules)


(82)

import, export

CommonJS

// app.js
var utils = require("./utils");
utils.hello();              // Hello, world!
console.log(utils.answer);  // 42
// utils.js
function hello() { console.log("Hello, world!"); }
var answer = 42;
module.exports = { hello: hello, answer: answer };

(83)

import, export

ES6

// app.js
import utils from "./utils";
utils.hello();              // Hello, world!
console.log(utils.answer);  // 42
// utils.js
function hello() { console.log("Hello, world!"); }
var answer = 42;
export default { hello: hello, answer: answer };

(84)

import * as

ES6

// app.js
import * as utils from "./utils";
utils.hello();              // Hello, world!
console.log(utils.answer);  // 42
// utils.js
export function hello() { console.log("Hello, world!"); }
export var answer = 42;

(85)

import { ... }

ES6

// app.js
import { hello, answer } from "./utils";
hello();                    // Hello, world!
console.log(answer);        // 42
// utils.js
export function hello() { console.log("Hello, world!"); }
export var answer = 42;

(86)

END

We are hiring!
UNIPRO Inc.


ECMAScript 2015 Slideshows