導入:なぜSymbol.iteratorが重要なのか?
JavaScriptで配列や文字列を扱うとき、私たちは普段何気なく「for…of」ループを使っています。しかし、自分で作ったデータ構造を「for…ofで回せるようにしたい」と考えたことはありますか?
Symbol.iteratorは、JavaScriptの「繰り返し処理(イテレーション)」をカスタマイズするための強力なツールです。これを知ることで、独自のデータ構造を標準のループ構文に対応させることができ、コードの可読性と拡張性を大幅に向上させることができます。
基礎知識:イテレータとイテラブルとは?
JavaScriptの繰り返し処理を理解するには、2つの専門用語を知っておく必要があります。
1. イテラブル(Iterable)
「反復可能」なオブジェクトのことです。配列や文字列はこれに該当し、「for…of」を使って要素を順番に取り出すことができます。
2. イテレータ(Iterator)
「次に何を処理するか」を管理するオブジェクトです。{ value: 値, done: true/false } という形式のオブジェクトを返す「next()」メソッドを持っています。
Symbol.iteratorは、オブジェクトが「イテラブル」であることを示すための「目印(キー)」です。これに特定のメソッドを実装することで、JavaScriptのエンジンはそのオブジェクトを「繰り返し可能なもの」として認識します。
実装:Symbol.iteratorを実装する手順
自作のオブジェクトをfor…ofで回せるようにするには、以下のルールを守る必要があります。
1. オブジェクトの中に [Symbol.iterator] というキーでメソッドを定義する。
2. そのメソッドが「next()」メソッドを持つオブジェクトを返すようにする。
3. next() は必ず { value: …, done: … } という形式のオブジェクトを返す。
サンプルプログラム:独自のカウントダウン機能
以下は、指定した数値から0までカウントダウンする独自のイテレータの実装例です。コピーしてブラウザのコンソールなどで実行してみてください。
// カウントダウンを行うオブジェクトを作成
const countdown = {
start: 3,
[Symbol.iterator]() {
let current = this.start;
// イテレータオブジェクトを返却
return {
next() {
if (current >= 0) {
// まだ値がある場合は値を返し、doneをfalseにする
return { value: current--, done: false };
} else {
// 終了した場合は値をundefinedにし、doneをtrueにする
return { done: true };
}
}
};
}
};
// for...of ループで動作確認
for (const num of countdown) {
console.log("現在のカウント:", num); // 3, 2, 1, 0 と順番に出力される
}
応用・注意点:現場での活用と落とし穴
1. ジェネレーター関数の活用
上の例ではnextメソッドを自作しましたが、現場では「function(ジェネレーター関数)」を使うのが一般的です。yieldキーワードを使えば、もっと簡潔に書くことができます。
2. 無限ループに注意
イテレータを自作する際、doneを適切にtrueにしないと、for…ofループが止まらなくなり、ブラウザがフリーズする原因になります。必ず終了条件を明確に設定しましょう。
3. どこで使うか?
通常の配列操作には不要ですが、例えば「巨大なデータのリスト」や「APIからページネーションで取得するデータ」を扱う際、一度にすべてを読み込まず、必要な分だけを逐次処理するような設計にする場合にSymbol.iteratorは非常に強力な武器となります。