22. 列挙 ( for ? of )
ES3 (BAD)
var xs = [2, 3, 5];
for (var i in xs) {
console.log(xs[i]);
}
javascript - Why is using "for...in" with array iteration such a bad idea?
- Stack Over?ow
var xs = []; xs[5] = 42; のようなパターンでアウト
Array.prototype を弄るわるいライブラリがいるとアウト
22 / 85
23. 列挙 ( for ? of )
ES3 (GOOD)
var xs = [2, 3, 5];
for (var i = 0; i < xs.length; ++i) {
console.log(xs[i]);
}
23 / 85
24. 列挙 ( for ? of )
ES5
var xs = [2, 3, 5];
xs.forEach(function (x, i) {
console.log(x);
});
Array.prototype.forEach を使う
コールバック関数の第 2 引数には添字が入っている
24 / 85
25. 列挙 ( for ? of )
ES6
var xs = [2, 3, 5];
for (var x of xs) {
console.log(x);
}
配列だけでなくジェネレータ(後述)なども列挙できる
Symbol.iterator (後述)を利用すれば独自のオブジェクトも列挙でき
る
25 / 85
29. 新しい正規表現のフラグ ( 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
sticky ?ag ( lastIndex から順次検索)
console.log(/? ? *? /.test("? ? ? ? ? ")); // false
console.log(/? ? *? /u.test("? ? ? ? ? ")); // true
参考:Unicode-aware regular expressions in ECMAScript 6 · Mathias
Bynens
29 / 85
30. 分割代入
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;
30 / 85
31. 分割代入
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;
xs , obj が 1 回しか登場しないのが利点
関数の戻り値を扱う場合一時変数に代入する必要がない
変数名が長い場合にもアドバンテージ
31 / 85
33. ブロックスコープ変数 ( let )
ES3 / ES5 (BAD)
var s = "foo";
{
var s = "bar";
console.log(s); // bar
}
console.log(s); // bar
ES5 以前の JavaScript には関数スコープしか存在しない
33 / 85
34. ブロックスコープ変数 ( let )
ES3 / ES5 (GOOD)
var s = "foo";
(function () {
var s = "bar";
console.log(s); // bar
})();
console.log(s); // foo
関数の即時実行でスコープを実現する
34 / 85
35. ブロックスコープ変数 ( let )
ES6
var s = "foo";
{
let s = "bar";
console.log(s); // bar
}
console.log(s); // foo
let で変数を宣言するとブロックスコープを持つ変数になる
35 / 85
36. let と for
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
}
クロージャが同じ i を参照している
36 / 85
37. let と for
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
}
関数の即時実行でスコープを切る
37 / 85
38. let と for
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
}
for の初期化節で let を使う
38 / 85
40. 関数 (Functions)
アロー関数 ( (x, y) => { ... } )
クラス ( class , extends , super )
ジェネレータ ( function * , yield )
40 / 85
41. アロー関数
ES3 / ES5
var myRandom = function (x, y) {
var range = y - x;
return x + (Math.random() * range);
};
var pow2 = function (x) { return x * x };
41 / 85
42. アロー関数
ES6
var myRandom = (x, y) => {
var range = y - x;
return x + (Math.random() * range);
};
var pow2 = x => x * x;
引数が 1 個の場合 (x) => { ... } を x => { ... } と略記可
(foo) => { return bar; } を (foo) => bar と略記可
アロー記法と function 記法では this の扱いについて違いがある
42 / 85
43. アロー関数( this の扱い)
ES3 / ES5 (BAD)
var obj = {
f: function () {
setTimeout(function () {
console.log(this.x);
}, 1000);
},
x: 42
};
obj.f(); // undefined
this !== obj となってしまう
43 / 85
44. アロー関数( this の扱い)
ES3 (GOOD)
var obj = {
f: function () {
var that = this;
setTimeout(function () {
console.log(that.x);
}, 1000);
},
x: 42
};
obj.f(); // 42
this に別名を付ける
44 / 85
55. ジェネレータの列挙
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
}
for ? of でジェネレータの値を列挙できる
55 / 85
56. ジェネレータの展開
ES6
function * range(n) {
for (var i = 0; i < n; ++i) yield i;
}
console.log([...range(2), ...range(3)]); // [ 0, 1, 0, 1, 2 ]
... でジェネレータを展開できる
56 / 85
58. 型付き配列
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 ]
XHR で取得したバイナリを扱う際に有用
WebGL を使う際にも利用する
new の際に配列長か Array か ArrayBuffer を与える
58 / 85
59. 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]
型付き配列は view(窓)に過ぎず、実体は ArrayBuffer である
ArrayBuffer を共有すると内容も共有される
59 / 85
60. 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
C の構造体のような複合データを扱う際には DataView を用いるとよい
get 系関数の第 2 引数、set 系関数の第 3 引数にはエンディアンを指定する
デフォルトはビッグエンディアン
リトルエンディアンなら true を指定
60 / 85
61. 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); // {} {}
いわゆる辞書型
キーにオブジェクトを使うことができる
61 / 85
62. 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
キーを弱参照で持つ Map
キーを列挙することはできない
62 / 85
63. 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
いわゆる集合型
列挙は挿入順
63 / 85
64. 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
キー(値)を弱参照で持つ Set
WeakMap と同じく列挙不可
64 / 85
65. 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 }
メタプログラミングに使えるらしい
参考:Meta programming with ECMAScript 6 proxies
65 / 85
66. 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 }
参考:ecmascript 6 - What does the Re?ect object do in JavaScript? -
Stack Over?ow
66 / 85