イテレーター・反復可能オブジェクト・ジェネレーター
- イテレーター(iterator)
- 反復可能オブジェクト(iterable object)
- ジェネレーター(generator)
- ヘルパーメソッド
- iterableObject.map(function)
- iterableObject.filter(function)
- iterableObject.take(n)
- iterableObject.drop(n)
- iterableObject.flatMap(function)
- iterableObject.reduce(function)
- iterableObject.toArray()
- iterableObject.forEach(function)
- iterableObject.some(function)
- iterableObject.every(function)
- iterableObject.find(function)
- Iterator.from(iterator)
イテレーター(iterator)
イテレーターとは
イテレーター(iterator) は繰り返し処理を実現するための下記特徴を持つオブジェクトです。
next()
メソッドを持つ。next()
の戻り値は{ value: value, done: done }
の形式。value
は次の値、done
はループが継続する場合はfalse
、終了する場合はtrue
を返す。
イテレーターの実装例
下記がイテレーターの実装例です。
class MyRangeIterator { constructor(n, m) { this.n = n; this.m = m; } next() { return { value: this.n, done: this.n++ > this.m }; } }
反復可能オブジェクト(iterable object)
反復可能オブジェクトとは
反復可能オブジェクト(iterable object) は下記の特徴を持つオブジェクトです。
- [Symbol.iterator]() というメソッドを持つ。
- [Symbol.iterator]() メソッドはイテレーターを返却する。
for (...of...)
でループ参照することができる。
反復可能オブジェクトの実装例
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)
ジェネレーターとは
ジェネレーター(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 }
ヘルパーメソッド
ES2025 で反復可能オブジェクトに下記のメソッドがサポートされました。
iterableObject.map(function)
それぞれの要素に関数を実行した反復可能オブジェクトを返します。
for (var n of myRange(1, 5).map(value => value * 2)) {
console.log(n); // 2, 4, 6, 8, 10
}
iterableObject.filter(function)
関数の結果が true
となる要素からなる反復可能オブジェクトを返します。
for (var n of myRange(1, 5).filter(value => value % 2 == 0)) {
console.log(n); // 2, 4
}
iterableObject.take(n)
最初の n 個のみを抽出した反復可能オブジェクトを返します。
for (var n of myRange(1, 5).take(3)) { console.log(n); // 1, 2, 3 }
iterableObject.drop(n)
最初の n 個を読み飛ばした反復可能オブジェクトを返します。
for (var n of myRange(1, 5).drop(3)) {
console.log(n); // 4, 5
}
iterableObject.flatMap(function)
それぞれの要素に関数を実行した結果をフラットにした反復可能オブジェクトを返します。複数要素からなる配列を返却すると、要素の数が増えます。下記の例では 1 から 1 と 1.5、2 から 2 と 2.5, ... を生成しています。
for (var n of myRange(1, 5).flatMap(value => [value, value + 0.5])) {
console.log(n); // 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5
}
iterableObject.reduce(function)
それぞれの要素に対して逐次的に関数を実行し、その最終結果を返します。下記の例で sum
は前回の関数の戻り値、value
は今回の要素を示します。下記の様にして 1 から 5 の合計 15 を求めることができます。
console.log(
myRange(1, 5).reduce((sum, value) => sum + value) // 15
);
iterableObject.toArray()
反復可能オブジェクトを配列に変換します。
console.log(
myRange(1, 5).toArray() // [1, 2, 3, 4, 5]
);
iterableObject.forEach(function)
反復可能オブジェクトに対してループ処理を行います。
myRange(1, 5).forEach((n) => {
console.log(n) // 1, 2, 3, 4, 5
});
iterableObject.some(function)
それぞれの要素に対して関数を実行し、結果がひとつでも true であれば true を返します。下記の例では 1 から 5 の中にひとつでも 3 と等しいものがあれば true
を返します。
console.log(
myRange(1, 5).some(v => v == 3) // true
);
iterableObject.every(function)
それぞれの要素に対して関数を実行し、結果がすべて true であれば true を返します。下記の例では 1 から 5 の要素がすべて 10 未満であれば true
を返します。
console.log(
myRange(1, 5).every(v => v < 10) // true
);
iterableObject.find(function)
それぞれの要素に対して関数を実行し、結果が true
であった要素の個数を返します。下記の例では 1 から 5 の要素の内、3 以上である要素の個数を返します。
console.log(
myRange(1, 5).find(v => v >= 3) // 3
);
Iterator.from(iterator)
イテレーターを反復可能オブジェクトに変換します。
class MyRangeIterator { constructor(n, m) { this.n = n; this.m = m; } next() { return { value: this.n, done: this.n++ > this.m }; } } const iterator = new MyRangeIterator(1, 5); // イテレーター const iterable_object = Iterator.from(iterator); // 反復可能オブジェクト for (var n of iterable_object) { console.log(n); }