生成器函数中的委派yield(yield star,yield *)

41

ECMAScript 6应该会引入生成器函数和迭代器。生成器函数(具有function*语法)返回一个迭代器。迭代器有一个next方法,当重复调用时,执行生成器函数体,每次在yield运算符处暂停并恢复执行。

ECMAScript 6生成器的维基页面还介绍了“委派yield”yield*运算符,如下所示:

yield*运算符委派给另一个生成器。这提供了一种方便的机制来组合生成器。

“委派给另一个生成器”是什么意思?我怎么使用yield*“方便地组合生成器”?

[您可以在Node v0.11.3中使用--harmony-generators标志玩转生成器。]


1
wiki中提到:“这类似于对生成器的for-in循环”,因此,yield* generator应类似于for (i of generator) { yield i; } - Felix Kling
2
如果你了解Python,那么这就是yield from的作用。 - georg
产生器炸弹? (function*_(){yield*(_())})().next() - Evan Carroll
3个回答

53

委托给另一个生成器意味着当前生成器停止自己产生值,而是产生由另一个生成器产生的值,直到它耗尽为止。然后,如果有任何值,它将恢复生成自己的值。

例如,如果secondGenerator()产生从1015的数字,而firstGenerator()产生从15的数字,但在产生2之后委托给secondGenerator(),那么firstGenerator()产生的值将是:

1, 2, 10, 11, 12, 13, 14, 15, 3, 4, 5

function* firstGenerator() {
    yield 1;
    yield 2;
    // Delegate to second generator
    yield* secondGenerator();
    yield 3;
    yield 4;
    yield 5;
}

function* secondGenerator() {
    yield 10;
    yield 11;
    yield 12;
    yield 13;
    yield 14;
    yield 15;
}

console.log(Array.from(firstGenerator()));


11
好的。回想起来很显然,但我发现规格说明书很难读懂。一个改进的方法是添加产生你提到结果的示例代码。 - qubyte

5
委派生成器并不一定只能委派给另一个生成器,而是可以委派给任何迭代器。因此第一个答案有些不确定。考虑以下简单的例子:

function* someGenerator() {
    yield 0;
    yield [1,2,3];
    yield* [1,2,3];
}

for (v of someGenerator()) {
    console.log(v);
}

生成器本身没有其他功能,但yield* [1, 2, 3]会委托给Array.prototype[@@iterator]方法。


3
function *gimme1to2_10to15_3to5() {
    var ten = gimme10to15();
    yield 1; yield 2;
    for (var i = 10; i <= 20; i++)
        yield *ten;
    yield 3; yield 4; yield 5;
    }

function *gimme10to15() {
    for (var i = 10; i <= 15; i++)
        var x = yield i;
    }

let gen = gimme1to2_10to15_3to5();

var ar = [];
for (var i = 0; i < 12; i++)
    {
    var r = gen.next();
    ar [i] = r.value + (r.done ? "!" : "..");
    }
console.log (ar.join (", "));

结果为:
1.., 2.., 10.., 11.., 12.., 13.., 14.., 15.., 3.., 4.., 5.., undefined!

注意事项

  1. 使用yield *函数从内部生成器请求11个值,但只收到应有的10..15个值。多余的yield *调用没有效果。

  2. 内部生成器的done值对其调用者返回的done没有影响。

  3. 输出最后显示undefined!,因为测试循环编写为超过所需数量的一个值,以显示生成器的done = true

  4. 此输出来自ES6测试场地Babel,上面展示的语义应该被视为临时的,截至2016年2月5


1
yield *tenyield* ten 是一样的吗? - Ozymandias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接