各種スクリプト言語で、概ね「yield」というキーワードがあれば、
同様の機能があると思われます。
各種言語で概ね共通したイメージとしては、
・関数を呼び出した時に、「yield文(や関数)」まで実行。
・該当関数の処理は一端停止しつつ、yieldの引数(等)の値を返す。
・次に同じ関数を呼び出した際には、一端停止したのを解除して、その続き(のステップ/行)から処理を再開
という感じです。
ECMAScript6では「yield演算子」という名称となっています。
function* sampleGenerator(i) { yield i + 1; // ここで i+1を返して、関数は(次の呼び出しまで)一端停止 yield i + 2; // ここで i+2を返して、関数は(次の呼び出しまで)一端停止 yield i + 3; // ここで i+2を返して、関数は(次の呼び出しまで)一端停止 } var gen = sampleGenerator(10); hm.debuginfo(gen.next().value); // 10 hm.debuginfo(gen.next().value); // 11 hm.debuginfo(gen.next().value); // 12
function* idMaker(){ var index = 0; while(true) { yield index++; } } var gen = idMaker(); hm.debuginfo(gen.next().value); // 0 hm.debuginfo(gen.next().value); // 1 hm.debuginfo(gen.next().value); // 2
yieldの中で別のyieldを使用する場合には、
「yield*」といった独特の表記となります。
function* anotherGenerator(i) { yield i + 1; yield i + 2; yield i + 3; } function* generator(i){ yield i; yield* anotherGenerator(i); yield i + 10; } var gen = generator(10); hm.debuginfo(gen.next().value); // 10 hm.debuginfo(gen.next().value); // 11 hm.debuginfo(gen.next().value); // 12 hm.debuginfo(gen.next().value); // 13 hm.debuginfo(gen.next().value); // 20
「yield」(より厳密には「yield.next()」)が返しているものは、
・{ value : 今回の値, done:false }
もしくは、
・{ done:true }
です。
function* sampleGenerator() { yield "あ" yield "い" yield "う" } var gen = sampleGenerator(); hm.debuginfo(gen.next()); // {"value":"あ","done":false} hm.debuginfo(gen.next()); // {"value":"い","done":false} hm.debuginfo(gen.next()); // {"value":"う","done":false} hm.debuginfo(gen.next()); // {"done":true}
「for...of」先述した仕組みで「done:true」が出現するまで、
1つ1つ要素を出すといったことに対応しているため、以下のような順次処理が可能です。
function* sampleGenerator() { yield "あ" yield "い" yield "う" } for (let e of sampleGenerator()) { hm.debuginfo(e); } // "あ" // "い" // "う" for (let e of sampleGenerator()) { hm.debuginfo(e); } // "あ" // "い" // "う"
2つ「for...of」があります。
2番めのfor...ofの際、ジェネレータがちゃんとリセット(再び最初から実行)されていることに注目してください。