了解Javascript的生成器



我有一段代码:

function * input(){
let array = [];
while(true) {
array.push(yield array);
}
}
var gen = input();
console.log(gen.next("A"))
console.log(gen.next("B"))
console.log(gen.next("C"))
console.log(gen.next("D"))

当你运行它时,你会得到以下输出:

{ value: [], done: false }
{ value: [ 'B' ], done: false }
{ value: [ 'B', 'C' ], done: false }
{ value: [ 'B', 'C', 'D' ], done: false }

为什么结果的第一行不包括数组中的A?这一页上有一个解释https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*#将参数传入生成器。评论说

next()的第一个调用从函数开始执行直到第一个收益率报表

但从我的测试来看,这似乎不正确。我的测试代码是:

function* logGenerator() {
console.log("before yield in function");
yield 1;
console.log("filler 1");
yield 2;
console.log("filler 2");
yield 3;
console.log("filler 3");
}
var gen = logGenerator();
console.log(gen.next());
console.log("-----------------");
console.log(gen.next());
console.log("-----------------");
console.log(gen.next());
console.log("-----------------");
console.log(gen.next());

结果是:

before yield in function
{ value: 1, done: false }
-----------------
filler 1
{ value: 2, done: false }
-----------------
filler 2
{ value: 3, done: false }
-----------------
filler 3
{ value: undefined, done: true }

正如您所看到的,第一个next()不仅执行了第一个yield之前的语句,而且还执行了第一条yield语句。所以这个理论不能解释我的问题。有人能帮我指明正确的方向吗?提前谢谢。

考虑您以这种方式重写的第一个生成器。

function * input(){
let array = [];
while(true) {
var thingToAdd = yield array;
console.log(thingToAdd);
array.push(thingToAdd);
}
}
var gen = input();
console.log(gen.next("A"))
console.log(gen.next("B"))
console.log(gen.next("C"))
console.log(gen.next("D"))

为什么"A"从未被添加到数组中,这不是更清楚了吗?生成器的第一次执行在修改数组之前的第一个yield语句处停止。当执行返回到生成器时,传入的值为"B"。在您的代码中也发生了相同的动态,首先计算array.push(yield array);内部表达式,因此yield在访问push之前停止执行。

我相信,如果你想让生成器尊重你传递的第一个值,你需要在不带任何参数的情况下调用.next()一次。我看到的每一个例子都是这样的。

此外,阅读本文的"发送"部分可以说明您的情况。

请注意,该模型适用于问答类型的交互,因为在提出问题之前,我们无法得到答案,并且所有后续的next调用都将传递上一个问题的答案并检索下一个问题。

var q1 = gen.next();
console.log(q1);
var a = userInput();
var q2 = gen.next(a);
console.log(q2);
var a2 = userInput();
...
function * foo () {
var i = 0
yield i
i += 1
yield i
i += 1
i += 2
yield i
}
var gen = foo()
console.log(gen.next()) // 0
console.log(gen.next()) // 1
console.log(gen.next()) // 4

请注意,var gen = foo()仅创建生成器的一个实例。这是.next()的第一次调用,它启动了生成器的执行。生成器执行直到到达yield语句,并返回该yield语句的值。此时,生成器暂停,直到执行.next()的另一次调用为止。

因此,在您的示例中,一切都按预期进行。在第一个示例中,第一个yield语句返回空数组。在下一个.next()中,使用传入的值填充数组,然后生成该数组。代码中:

function * foo (param) {
var array = []
// do nothing with param
yield array
array.push(param) // 'B'
yield array
array.push(param) // 'C'
yield array
array.push(param) // 'D'
yield array
}

这与文档匹配:

如果将可选值传递给生成器的next()方法,则该值将成为生成器当前yield操作返回的值。

相关内容

  • 没有找到相关文章

最新更新