既に見たように、ジェネレータ関数の内部ではyield式によって、呼び出し側に値と制御をいったん戻す。基本はこれなのだが、yield*式によって別のジェネレータ関数の反復処理を行ったり、yield式で中断した処理から再開する際に呼び出し側から何らかの値を与えたりできる。
最初にyield*式のサンプルを見てみよう。
function* generator1(from, to) {
yield from;
yield* generator2(from+1, to-1);
yield to;
}
function* generator2(from, to) {
var array = [ "", "i", "ii", "iii", "iv", "v",
"vi","vii", "viii", "ix", "x" ]
while(from <= to) {
yield array[from++];
}
}
for (var i of generator1(1,5)) {
console.log(i);
}
yield*式は、この式に与えたイテレート可能なオブジェクトを反復処理し、イテレート可能なオブジェクトから返された値を一つずつ呼び出し側に返送するものだ。
このサンプルでは、ジェネレータ関数が二つある。generator1ジェネレータ関数は指定した範囲の最初と最後の値は自身でyieldしているが、その間の値については「yield* generator2(from+1, to-1)」としてgenerator2ジェネレータ関数を利用している。generator2ジェネレータ関数では、与えられた範囲のローマ数字を返すようにしている(範囲外の数値が与えられた場合のエラー処理はここでは割愛)。
これを実行すると、「1」「ii」「iii」「iv」「5」が順に表示される。
次に、yield式に呼び出し側が値を渡す例を見てみよう。
function* generator(from, to) {
var msg = "";
while (from <= to) {
if (msg == "terminate") {
return;
} else if (msg == "skip") {
from++; // 変数fromをインクリメントすることでスキップ
}
msg = yield from++;
}
}
var gen = generator(1,3);
console.log(gen.next().value);
console.log(gen.next("terminate").value);
console.log(gen.next().value)
ここではnextメソッドに文字列「terminate」を渡すと反復処理を終了し、文字列「skip」を渡すと変数fromの値をインクリメントするようにしている。呼び出し側からの値を受け取るには「変数 = yield ……」のような書き方をする。C#では反復子ブロックにはreturn文を書けないが、ES2015ではreturn文に到達するとジェネレータ関数が終了し、return文に与えた値をvalueプロパティの値に、doneプロパティの値をtrueにしたオブジェクトが呼び出し側に返送される。
反復処理の継続/終了などを、呼び出し側の要因で決定したいなどの場合には、この形式のyield式が役に立つだろう。
本稿では、ジェネレータ関数とこれに関連してfor-of文、yield式について見た。C#開発者の方であれば、その概念についても容易に理解できるはずなので、ぜひとも覚えておこう。なお、詳細についてはES2015の仕様を見てもよいが、MDN(Mozilla Developer Network)の該当ページが分かりやすい。
Copyright© Digital Advantage Corp. All Rights Reserved.