社内LT用です。
Iteratorをおさらい
ary = [0, 1, 2];
it = ary[Symbol.iterator]()
console.log(it.next());
// { done: false, value: 0 }
console.log(it.next());
// { done: false, value: 1 }
console.log(it.next());
// { done: false, value: 2 }
console.log(it.next());
// { done: true, value: undefined }
for of構文によるループ
ary = [0, 1, 2];
it = ary[Symbol.iterator]();
for (value of it) {
console.log(value);
// 0, 1, 2
}
イテレーターとは、一連の処理中において現在の処理位置を把握しつつ、コレクション中の項目へ一つずつアクセスする方法を備えたオブジェクトのことです。
MDN イテレーターとジェネレーター より
JavaScript においては、イテレーターは一連の処理中の次の項目を返す next() メソッドを提供するオブジェクトです。このメソッドは done と value という 2 つのプロパティを持つオブジェクトを返します。
MDN イテレーターとジェネレーター より
next() を 実装してみる
const generateIterator = function() {
let count = 0;
return {
next: function() {
if (count > 2) return { done: true, value: void(0) };
return { done: false, value: count++ }
}
}
}
const it = generateIterator();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
{ done: boolean, value: any }
はIteratorResultオブジェクト
sampleIteratorは for of
によるループでは利用できない
iterableになるために、オブジェクトは@@iteratorメソッドを実装する必要があります。これは、オブジェクト(または、prototype chainオブジェクトの一つ)がSymbol.iteratorキーのプロパティを持つ必要があります。:
MDN 反復処理プロトコル より
どうする
- IteratorをさらにIterableにする必要がある
-
Iterator[Symbol.iterator]()
を持つ必要がある - Iteratorそのものが返り値となる関数
- ArrayやMapはもともとIterable
-
[Symbol.iterator]()
を実装する
const generateIterator = function() {
let count = 0;
return {
[Symbol.iterator]: function() {
return this;
},
next: function() {
if (count > 2) return { done: true, value: void(0) };
return { done: false, value: count++ }
}
}
};
const it = generateIterator();
// for of
for (value of it) {
console.log(value);
// 0, 1, 2
}
だるい
- そこでGeneratorですよ
Generator
function* it() {
let count = 0;
while(true) {
if (count > 2) break;
yield count++;
}
}
for (value of it()) {
console.log(value);
// 0, 1, 2
}
超スッキリ
ここが違う
- functionキーワードの後に
*
-
return
の代わりにyield
yield
- IteratorResultを返す
- yieldに続く式を評価した結果が
value
に代入される - yield式によって関数は実行を停止する
-
next()
が呼ばれると実行が再開する - 再開後
return
もしくは何もせずに関数が終了した場合done:true
でIteratorResultが返る
-
Iteratorの利点
- オブジェクトや関数をIterableにすることで
for of
に突っ込める - スプレッド演算子による式展開が行える
- 分割代入が行える
- range関数が簡単にかける
スプレッド演算子による式展開が行える
function* it() {
yield "hoge";
yield "hige";
yield "fuga";
}
console.log(...it());
// hoge hige fuga
分割代入が行える
function* it() {
yield* [0, 1, 2];
}
[a, b, c] = it();
console.log(a); // 0
console.log(b); // 1
console.log(c); // 2
range関数が簡単にかける
function* range(start, end) {
let n = start;
while(true) {
yield n++;
if (n > end) break;
}
}
const r = [...range(3, 6)];
console.log(r); // [3, 4, 5, 6]