JavaScript/Iterator
Iterator オブジェクトは、JavaScript における反復可能な操作を行うための標準的なプロトコルを提供します。配列やマップなどのデータ構造を順番に処理する際に利用されます。
Iteratorオブジェクト
編集Iteratorオブジェクトは、イテレーター(反復子)として機能し、next()
メソッドを使用して値を順次取得します。JavaScript の多くの組み込みオブジェクトは、反復可能なプロトコルに準拠しています。
- Iteratorの基本構造
const iterator = { next: function() { // ロジックを記述 return { value: ..., done: ... }; } };
特徴
編集- 値の逐次取得:
next()
メソッドを呼び出すたびに次の値が返されます。 - 終了判定: 反復が終了すると
done: true
が返されます。 - 反復可能オブジェクトとの互換性:
[Symbol.iterator]
メソッドを持つオブジェクトは、イテレーターとして利用できます。
使用例
編集カスタムIterator
編集独自のイテレーターを作成することで、任意のロジックで反復可能なオブジェクトを作成できます。
function createIterator(array) { let index = 0; return { next: function() { if (index < array.length) { return { value: array[index++], done: false }; } else { return { value: undefined, done: true }; } } }; } const myIterator = createIterator([1, 2, 3]); console.log(myIterator.next()); // { value: 1, done: false } console.log(myIterator.next()); // { value: 2, done: false } console.log(myIterator.next()); // { value: 3, done: false } console.log(myIterator.next()); // { value: undefined, done: true }
反復可能オブジェクト
編集配列や文字列などの組み込みオブジェクトは、イテレーターを実装しています。
const array = [10, 20, 30]; const iterator = array[Symbol.iterator](); console.log(iterator.next()); // { value: 10, done: false } console.log(iterator.next()); // { value: 20, done: false } console.log(iterator.next()); // { value: 30, done: false } console.log(iterator.next()); // { value: undefined, done: true }
イテレーターとループ
編集イテレーターは for...of
ループと密接に連携して動作します。
const array = ['a', 'b', 'c']; for (const value of array) { console.log(value); // 'a', 'b', 'c' }
プロパティとメソッド
編集Symbol.iterator
編集反復可能オブジェクトには [Symbol.iterator]
メソッドが存在し、これが呼び出されるとイテレーターオブジェクトを返します。
const iterable = { [Symbol.iterator]: function() { let step = 0; return { next: function() { step++; if (step <= 3) { return { value: step, done: false }; } else { return { value: undefined, done: true }; } } }; } }; for (const value of iterable) { console.log(value); // 1, 2, 3 }
next()
編集反復を次の値に進め、オブジェクトを返します。返されるオブジェクトには value
と done
プロパティが含まれます。
使用例
編集カウントダウンの例
編集カスタムイテレーターを作成してカウントダウンを実装します。
function countdown(from) { return { [Symbol.iterator]: function() { let count = from; return { next: function() { if (count >= 0) { return { value: count--, done: false }; } else { return { value: undefined, done: true }; } } }; } }; } for (const value of countdown(5)) { console.log(value); // 5, 4, 3, 2, 1, 0 }
注意事項
編集- 反復可能オブジェクトを利用する際は、
done: true
が返されるタイミングに注意が必要です。 for...of
ループはdone: true
のときに自動的に終了します。
Iterator Helpers
編集ES(ECMAScript)の Iterator Helpers は、イテレータや非同期イテレータを操作するための便利なメソッドの集合で、繰り返し処理をより簡単に行えるように設計されています。この提案は ECMAScript に導入された新しい機能(ES2024 など)で、配列やマップのようなイテラブルに対して使える高度な操作を、標準化された方法で提供します。
背景
編集従来の ECMAScript では、イテレータを操作するために手動でループや for...of
を使用する必要がありました。特定の操作(フィルタリング、マッピング、合計の計算など)を行うには、コードが複雑になることがありました。Iterator Helpers は、こうした操作を簡潔に実現するためのメソッドを提供します。
主な特徴
編集Iterator Helpers は、以下のようなメソッドをイテレータ(Iterator
または AsyncIterator
)に追加します。
Iterator.prototype.constructor
編集constructor
は、Iteratorオブジェクトのインスタンスを作成するメソッドです。通常、直接呼び出すことはなく、新しいIteratorを生成する際に内部的に使用されます。
- 書式
- Iteratorは抽象クラスであり new 直接インスタンス化されることはなく、コレクションの .valiues() / .entries() メソッドや function*(ジェネレータ)で生成します。
- 例
const myIterator = [1, 2, 3].values();
Iterator.prototype.drop
編集drop
メソッドは、指定された数の要素をイテレータからスキップします。
- 書式
iterator.drop(count)
- 例
const iterator = [1, 2, 3, 4, 5].values(); const droppedIterator = iterator.drop(2); // droppedIterator は [3, 4, 5] を含む
Iterator.prototype.every
編集every
メソッドは、イテレータのすべての要素が指定された条件を満たすかどうかをチェックします。
- 書式
iterator.every(callbackFn)
- 例
const numbers = [2, 4, 6, 8].values(); const allEven = numbers.every(num => num % 2 === 0); // allEven は true
Iterator.prototype.filter
編集filter
メソッドは、指定された条件に基づいて要素をフィルタリングします。
- 書式
iterator.filter(callbackFn)
- 例
const numbers = [1, 2, 3, 4, 5].values(); const evenNumbers = numbers.filter(num => num % 2 === 0); // evenNumbers は [2, 4] を含む
Iterator.prototype.find
編集find
メソッドは、指定された条件を最初に満たす要素を返します。
- 書式
iterator.find(callbackFn)
- 例
const numbers = [1, 2, 3, 4, 5].values(); const firstEven = numbers.find(num => num % 2 === 0); // firstEven は 2
Iterator.prototype.flatMap
編集flatMap
メソッドは、各要素に関数を適用し、結果を平坦化します。
- 書式
iterator.flatMap(callbackFn)
- 例
const words = ['hello', 'world'].values(); const chars = words.flatMap(word => word.split('')); // chars は ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'] を含む
Iterator.prototype.forEach
編集forEach
メソッドは、イテレータの各要素に対して関数を実行します。
- 書式
iterator.forEach(callbackFn)
- 例
const numbers = [1, 2, 3].values(); numbers.forEach(num => console.log(num)); // 1, 2, 3 を出力
Iterator.prototype.map
編集map
メソッドは、各要素に関数を適用し、新しいイテレータを返します。
- 書式
iterator.map(callbackFn)
- 例
const numbers = [1, 2, 3].values(); const squared = numbers.map(num => num * num); // squared は [1, 4, 9] を含む
Iterator.prototype.reduce
編集reduce
メソッドは、イテレータの要素を単一の値に畳み込みます。
- 書式
iterator.reduce(callbackFn, initialValue)
- 例
const numbers = [1, 2, 3, 4].values(); const sum = numbers.reduce((acc, num) => acc + num, 0); // sum は 10
Iterator.prototype.some
編集some
メソッドは、少なくとも1つの要素が指定された条件を満たすかどうかをチェックします。
- 書式
iterator.some(callbackFn)
- 例
const numbers = [1, 2, 3, 4, 5].values(); const hasEven = numbers.some(num => num % 2 === 0); // hasEven は true
Iterator.prototype.take
編集take
メソッドは、イテレータから指定された数の要素を取得します。
- 書式
iterator.take(count)
- 例
const numbers = [1, 2, 3, 4, 5].values(); const firstThree = numbers.take(3); // firstThree は [1, 2, 3] を含む
Iterator.prototype.toArray
編集toArray
メソッドは、イテレータの要素を配列に変換します。
- 書式
iterator.toArray()
- 例
const numbers = [1, 2, 3].values(); const array = numbers.toArray(); // array は [1, 2, 3]
注意
編集これらのメソッドは、ECMAScriptの最新の提案に基づいており、すべての環境でサポートされているわけではありません。実際の使用前に、ブラウザーや実行環境の互換性を確認してください。
非同期イテレータ用ヘルパー
編集非同期イテレータ(AsyncIterator
)に対しても同様のメソッドが提供されます。これにより、非同期データストリームの操作が簡単になります。
例: 非同期イテレータでの map
async function* asyncGen() { yield 1; yield 2; yield 3; } const result = asyncGen().map(async x => x * 2); console.log(await result.toArray()); // [2, 4, 6]
メリット
編集- 簡潔で読みやすいコード: 配列のようなイテラブル操作を、他のデータ構造(イテレータや非同期ストリーム)に対しても統一的に使える。
- メモリ効率の向上: 全データをメモリに展開する必要がないため、特に大規模なデータストリームの操作で有効。
- 非同期操作の統一: 非同期イテレータの扱いが簡単になる。
使用例: 組み合わせ
編集これらのヘルパーを組み合わせて高度な処理も可能です。
const iterator = [1, 2, 3, 4, 5].values(); const result = iterator .filter(x => x % 2 === 0) .map(x => x * 10) .take(1); console.log([...result]); // [20]
状態
編集Iterator Helpers は、現在の ECMAScript 標準(ES2024 以降)に含まれているか、あるいは最新の JavaScript エンジンで試験的に実装されている可能性があります。使用する際は、対応する環境(ブラウザや Node.js)のバージョンを確認してください。