イテレータ(iterator) は繰り返し処理を実現するための下記特徴を持つオブジェクトです。
next()
メソッドを持つ。
next()
の戻り値は { value: value, done: done }
の形式。
value
は次の値、done
はループが継続する場合は false
、終了する場合は true
を返す。
イテラブルなオブジェクト(iterable object) は下記の特徴を持つオブジェクトです。
for (...of...)
でループ参照することができる。
下記に簡単なサンプルを用意してみました。MyRangeIterator
がイテレータで、MyRange
がイテラブルなオブジェクトです。
class MyRangeIterator {
constructor(n, m) {
this.n = n;
this.m = m;
}
next() {
return { value: this.n, done: this.n++ > this.m };
}
}
class MyRange {
constructor(n, m) {
this.n = n;
this.m = m;
}
[Symbol.iterator]() {
return new MyRangeIterator(this.n, this.m);
}
}
for (var n of new MyRange(1, 5)) {
console.log(n); // 1, 2, 3, 4, 5
}
下記の様にイテレータ自体をイテラブルなオブジェクトにすることもできます。
class MyRange {
constructor(n, m) {
this.n = n;
this.m = m;
}
next() {
return { value: this.n, done: this.n++ > this.m };
}
[Symbol.iterator]() {
return this;
}
}
for (var n of new MyRange(1, 5)) {
console.log(n); // => 1, 2, 3, 4, 5
}
ジェネレータ(generator)はイテラブルなオブジェクトを簡単に生成できる仕組みです。
function*
の様に function
の後ろにアスタリスク(*
)をつけて定義します。
yield
または yield*
を用いて各ループの値を返却します。
ここでは myRange()
というジェネレータ関数を定義しています。ジェネレータ関数はジェネレータを返却します。ジェネレータはイテレータでもあり、イテラブルなオブジェクトでもあるオブジェクトです。
function* myRange(n, m) {
while (n <= m) {
yield n++;
}
}
for (var n of myRange(1, 5)) {
console.log(n); // => 1, 2, 3, 4, 5
}
yield *
にイテラブルなオブジェクトを指定するとその値を順番に返却してくれます。下記の例では yield*
でイテラブルなオブジェクトである Array() オブジェクトを指定しています。
function* myRange(n, m) { let array = new Array(); for (let i = n; i <= m; i++) { array.push(i); } yield* array; } for (var n of myRange(1, 5)) { console.log(n); // => 1, 2, 3, 4, 5 }