在生成器上使用展开语法时,为什么不会检索到返回值

7
我本来期望4会是序列数组的一部分,那为什么它被跳过了呢?

function* generate() {
  yield 1;
  yield 2;
  yield 3;
  return 4
}
let sequence = [...generate()];
console.log(sequence); // 1, 2, 3


2
@MisterJojo 有,但它会停止生成器。 - Gabriele Petrioli
1
@MisterJojo,return语句使用属性“done:true”标记生成器的结束。 - Mehdi Benmoha
1
是的,所有的迭代器都不使用 done:truefor (x of genarator()) 也不会得到它。 - Gabriele Petrioli
2
“done”标志被检查的方式忽略了返回的“value”。当“done”为“true”时,迭代完成。 - Pointy
3
“Done”:如果序列中的最后一个值已经被使用,则为真。 - Gabriele Petrioli
显示剩余6条评论
1个回答

5

生成器函数的return值不被视为序列的一部分。它作为最后一个.next()调用的返回值被返回,形式为{done: true, value:...},其中done: true表示序列已完成,应该不再调用.next()

为什么会这样呢?为什么不能只使用done标志设置为true来产生最后一个值呢?因为那样我们将无法使用迭代器表示一个序列 - 第一个.next()调用就已经产生了至少一个值。1

因此,通常情况下,生成器函数不返回任何东西(但是返回undefined),所有序列值都使用相同的语法进行生成 - 没有奇怪的特殊语法用于最后一个值2

function* generate() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
}

1:其他语言处理方式不同。在那些语言中,迭代器有一个单独的 .hasNext() 方法,在调用 .next() 之前被调用,或者它们的 .next() 方法要么返回一个值,要么抛出一个 StopIteration 异常。它们没有任何“最终值”。
2:如果必须预先知道一个值是否是最后一个并使用 return 而不是 yield,将使动态生成的序列的逻辑变得更加复杂。


1
如果将必须返回值的函数与含糊计算(例如 [])组合使用,则会发生这种情况。您将被困在一个无意义的返回值中。迭代器协议没有正式基础。它设计不良,忽略了几十年的计算机科学。 - user5536315
答案最好的部分是解释了为什么这种方法允许我们表示一个空序列,而不是问题所暗示的另一种选择。此外,针对您的脚注,您可以将next()视为一种std::optional,其中done!has_value - Patrick Roberts
1
@scriptum 我理解 IteratorResult 类型是通常迭代器使用情况下的一种简单的 Maybe - 你要么有 {done: false, value: …} 或者 {done: true}。此外,在 JS 中,生成器函数还可以作为协程,对于它们来说,最终值非常有用。 - Bergi

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