【问题标题】:Is the behavior of an array iterator defined if the underlying collection is added to during iteration?如果在迭代期间添加了底层集合,是否定义了数组迭代器的行为?
【发布时间】:2016-12-30 04:04:17
【问题描述】:

所以我有一个生成器函数应该从数组返回值的情况,但是该数组被填充在消耗生成器输出的同一个循环中。

具体场景是生成器返回自动密钥密码的密钥序列,其中每个新解码的字符都附加到密码密钥的末尾。我的实现有效,但我不确定它是否能保证有效,或者这是否是恰好对我有利的未定义行为示例。

本质上,下面的代码必须始终打印“a”、“b”、“c”、“d”、“e”,或者实现打印“a”、“b”、“ c”、“未定义”、“未定义”?我总是对修改正在迭代的集合持怀疑态度。

let a = ["a", "b", "c"];
let iter = function*() { yield* a; }();
console.log(iter.next().value);  // "a"
console.log(iter.next().value);  // "b"
a.push("d");
a.push("e");
console.log(iter.next().value);  // "c"
console.log(iter.next().value);  // "d" - but is this guaranteed?
console.log(iter.next().value);  // "e" - or is it?

已编辑:将标题从谈论“生成器”更改为“迭代器”,以更准确地反映问题的实质

【问题讨论】:

  • 我认为您需要在生成器的开头复制 a ,然后将 yield * 复制到副本中。
  • 是的,ES6 为所有集合指定了@@iterator() 的行为来处理突变。

标签: javascript iterator generator


【解决方案1】:

根据ES6 & Beyond,作者 Kyle Simpson,第103,yield * 接受一个 iterable,并“调用该迭代器的迭代器”。因此,您实际上是在询问 iterable 行为,而不是 generator 行为。

我很难找到有关修改底层数组时数组的迭代器如何反应的官方规范,但我必须假设这样一个基本功能已正确实现 - 即,根据您的实验,新的数组元素包含在可迭代的。当然,除非您使用的是 IE6。 :-)

因此,如果您希望您的生成器仅包含 a[] 的原始元素,则必须进行复制。例如

let iter = function*(a) {
  let copy = Array.from(a);
  yield * copy;
}

【讨论】:

  • 感谢术语的更正!你是对的,我的问题真的是关于可迭代的行为。我实际上得到了我想要的结果(我希望它产生所有元素,包括新添加的元素),我一直很好奇规范是否很好地定义了这种行为。从 Bergi 的评论中,现在我实际上搜索了正确的东西(数组迭代器,而不是生成器行为),我发现 %ArrayIteratorPrototype%.next() 应该始终评估当前长度(ecma-international.org/ecma-262/6.0/…
猜你喜欢
  • 2012-11-20
  • 1970-01-01
  • 2016-02-26
  • 2014-08-07
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
相关资源
最近更新 更多