Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【JavaScript】Generator

pythonなどのように、JavaScriptでもES6からGeneratorが使えるようです。

Generatorとは

呼び出すたびに値やオブジェクトを生成して返す仕組み。
Generatorを使うことで、オブジェクトや配列値の遅延評価を行うことができます。
遅延評価とは、必要なタイミングになるまで値の評価を遅延させることです。
この遅延評価は協力で、例えば無駄にオブジェクトをプールさせることなく、必要なときにジェネレータを呼び出してオブジェクトを生成、といったことができるようになります。

Generatorの使い方

Generatorを使って実現可能な概念の一つに、無限数列があります。
今回は要素が0を含む正の整数からなる無限配列を例として作ってみました。

function *infinityArrayGenerator(){
  var i = 0;
  while (true) {
    yield i++;
  }
}

var infinityArray = infinityArrayGenerator();

console.log(infinityArray.next().value); // 0
console.log(infinityArray.next().value); // 1
console.log(infinityArray.next().value); // 2
console.log(infinityArray.next().value); // 3
Generatorの生成
function *infinityArrayGenerator(){
  var i = 0;
  while (true) {
    yield i++;
  }
}

infinityArrayGeneratorはジェネレータです。
関数名の頭に*(アスタリスク)を付加することで、関数がGeneratorであることを表します。
Generatorではyieldキーワードを用います。Generatorではこのyieldが呼ばれた行で一旦値を評価して返し、Generatorが再度呼び出されるとこの地点から再び処理が再開されます。

var infinityArray = infinityArrayGenerator();

console.log(infinityArray.next().value); // 0
console.log(infinityArray.next().value); // 1
console.log(infinityArray.next().value); // 2
console.log(infinityArray.next().value); // 3

上のコードではinfinityArrayにジェネレータオブジェクトを格納し、
next()を呼ぶことでGeneratorに値の「生成」を行わせています。
next()を呼ぶたびにinfinityArray内ではyield時点で処理が一旦中断され、その時点でのiの値が返されます。

なぜGeneratorを使うのか

先程も述べましたが、Generatorの強みは遅延評価が可能な点にあります。
上記の例ではnext()を読んで初めて整数の生成が行われています。逆に言うと、next()が呼ばれるまでは値が生成されていません。infinityArrayは無限の整数列として振る舞うことができるにもかかわらず、それに必要なメモリ量を(現時点では)食いつぶしてはいません。

このように、「必要なときに必要なだけ」値・オブジェクトの生成を行ってくれるのがGeneratorの強みです。

(厳密にはメモリ容量もストレージ容量も有限なので、infinityArrayは無限になりませんが・・・)

おまけ

nextの引数に値を渡すと、渡した値をyield式の返戻値とすることができます。

function *infinityArrayGenerator(){
  var i = 0;
  while (true) {
    // nextに値を設定すればiに+100、デフォルトで+1
    var value = yield i ;
    i += value || 1;
  }
}

var infinityArray = infinityArrayGenerator();

console.log(infinityArray.next().value); // 0
console.log(infinityArray.next().value); // 1
console.log(infinityArray.next(100).value); // 101
console.log(infinityArray.next().value); // 102

参考文献

Generator - JavaScript | MDN

JavaScript の Promise: 概要  |  Web  |  Google Developers