ECMAScript 6 のドラフト仕様は、すでに現代の JavaScript 開発者にとって多くの喜びをもたらしています。以前の投稿では、新しい Collections クラスと for..of
の反復ループについて説明しました。この投稿では、for..of
ループと密接に関連する、ジェネレータ関数について説明します。
ジェネレータを使用する理由と方法を説明した優れた資料は、すでにホストされています。簡単に言えば、ジェネレータはイテレータを作成する特別な関数で、イテレータは next()
メソッドを持つオブジェクトで、このメソッドを呼び出すことで値を取得できます。ジェネレータ関数内では、キーワード yield
で next()
の値を指定します。yield
を使用すると、next()
が再び呼び出されるまで状態が保持され、ジェネレータ関数の実行が一時停止されます。その後、コードは再び起動し、別の値 yield
になるまで(またはジェネレータ関数が終了するまで)続行します。ジェネレータ関数には、フィボナッチ数列の数値を反復処理するなど、ジェネレータ関数の標準的なユースケースがいくつかあります。
基本を理解できたところで、JavaScript サンプルを使って詳細に進みましょう。ここでは、ジェネレータ操作の問題点、つまり「非常に小さい」点を取り上げています。全体にわたって多数のコメントが記載されており、読む前にライブ バージョンのコードを試すことができます。
では、このコードから重要なポイントは何でしょうか。
まず、ジェネレータを作成すると、それ自体の異なる状態を持つ一意のイテレータが生成されます。動作を制御できるジェネレータ コンストラクタにパラメータを渡すことができます。
次に、イテレータの next()
メソッドを呼び出すときにパラメータを渡すことができます。その値は、前回のイテレータ呼び出しの yield
ステートメントの左側に割り当てられます。これは、イテレータの出力を変化させるのに最適な方法です。ここでは、生成される単語が大文字であるかどうかをコントロールするために使用します。最初に生成される値に影響を与える場合は、ジェネレータのコンストラクタのパラメータを介して行います。
最後に、ジェネレータは有限または無限のイテレータを生成できます。無限イテレータを使用する場合は、yield
の値に基づくなんらかの終了条件があることを確認してください。特に、反復処理に for..of
を使用する場合は、誤って無限ループを記述してしまいがちです。next()
の呼び出しを介して有限イテレータを操作する場合は、返されるオブジェクトの .done
プロパティによって、反復が完了したかどうかが通知されます。
このサンプルとウェブ上で利用できる他のリソースを参考にして、ご自身のコードでジェネレータを使用する方法を考えてみてください。31 以降の Firefox と 39 以降の Chrome は、ジェネレータをネイティブにサポートしています。Regenerator プロジェクトでは他のブラウザ用のジェネレータ サポートが用意されており、Traceur を使用することもできます。
この記事のレビューに協力してくれた Erik Arvidsson に感謝します。