【问题标题】:ES6 Generators: First call to next()ES6 生成器:第一次调用 next()
【发布时间】:2017-02-05 13:26:03
【问题描述】:

我试图了解如何使用 ES6 生成器函数。除了在传递参数时进行空的 next() 函数调用这一概念之外,这似乎非常简单。这是我从 Mozilla 文档中引用的代码。

function* logGenerator() {
  console.log(yield);
  console.log(yield);
  console.log(yield);
}

var gen = logGenerator();

// the first call of next executes from the start of the function
// until the first yield statement

gen.next();
gen.next('pretzel'); // pretzel
gen.next('california'); // california
gen.next('mayonnaise'); // mayonnaise

据我了解,代码只执行到第一个 yield 语句,因此没有返回任何内容,然后我们第二次调用 next(),代码执行到包含第一个 yield 行的第二个 yield,因此pretzel 已记录到控制台。

如果是这种情况,在下面提到的代码中,0 如何在第一次调用next() 时登录?我在这里遗漏了一些东西:(

function* idMaker() {
  var index = 0;
  while (index < 3)
    yield index++;
}

var gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined

参考:Mozilla Documentation

【问题讨论】:

  • “直到 yield 语句”的意思是“产生第一个值”。

标签: javascript ecmascript-6


【解决方案1】:

我认为您遇到的是后增量运算符的行为,即index++。如果您将其更改为预增量运算符,即++index,它将按照您的预期运行。

不同之处在于,在计算表达式之后,后增量会将 1 添加到 index。在计算表达式之前,预增量会将 1 添加到 index,我认为这是您的目标。

【讨论】:

    【解决方案2】:

    嗯,生成器函数有点特殊。它们可以在整个执行过程中多次接受和返回值,而“普通”函数只能接受一组固定的参数,并返回一个值。在您的第一个示例中,它们用于将数据传递给生成器(多次传递参数),而在第二个示例中则相反(多次返回值)。

    考虑这个例子:

    function* foo() {
        console.log("before a");
    
        var a = (yield 123);
    
        console.log("after a");
    
        yield (a * 2);
    
        console.log("end of function");
    }
    
    var bar = foo();
    
    var x = bar.next(); // Runs until the first yield, prints 'before a'.
    console.log(x.value); // 123
    var y = bar.next(4); // Runs until the second yield, so prints 'after a'. 
    console.log(y.value); // 8
    var z = bar.next(); // prints 'end of function'.
    console.log(z.done); // true
    

    我们在第一个 next() 调用中不传递任何数据,让它一直运行到第一个 yield 语句。因为yield 123,调用(x.value)的结果是123。下次我们使用4作为参数值调用next(),我们在生成器函数中填写局部变量a。代码一直执行到下一个yield 语句并返回8 的结果。

    关于为什么 0 而不是 1 的解释,请参阅其他答案。

    【讨论】:

      【解决方案3】:

      据我了解,代码只执行到第一个 yield 语句,所以没有返回任何内容

      在 Mozilla 示例中,“yield”都返回 SOMETHING,它们返回未定义。这就像“返回”之后什么都没有,这也“返回”未定义。

      这里的特别之处在于,由于这是一个生成器函数,因此返回/生成发生在 log() 语句的中间。一旦“yield”语句开始执行,它们就会发生。这意味着它们在 log() 语句完成之前“跳出”当前函数,因此在第一次调用时没有任何内容到达控制台。换句话说,第一个收益导致函数*在日志语句有机会执行之前“跳出”。

      当您调用第二个 next() 时,执行将从上次停止的位置继续执行,但术语“yield”的值现在作为参数传递给 next()。因此,日志语句现在继续并打印该值。

      yield 的棘手部分是这种“瞬时”冻结,并且在 next() 上从上次冻结的完全相同的点继续,但术语“yield”现在具有作为参数传递给的值下一个()。如果 yield 发生在 log(yield) 之类的语句中,则冻结发生在包含语句能够执行之前。

      或者换句话说,我认为棘手的部分(这就是我重复自己的原因)是屈服语句导致函数在屈服语句完成之前返回。它只会在下一个 next() 上完成,通过让“yield”的值成为调用 next() 的参数。

      您的示例中的不同之处在于您的 log() 语句都发生在生成器函数之外,在 Mozilla 示例中它们发生在其中。因此,您的 logs() 将使用它们从调用 next() 中获得的值执行。由于您的 logs() 发生在生成器之外,因此您的任何 log() 语句都不会在中间中断。

      【讨论】:

        猜你喜欢
        • 2014-01-25
        • 2014-02-11
        • 2017-10-30
        • 1970-01-01
        • 2018-01-14
        • 2014-06-13
        • 1970-01-01
        • 2014-06-30
        • 2016-08-21
        相关资源
        最近更新 更多