ES6:在Set/Map迭代过程中从Set/Map中删除元素是否危险?

gav*_*koa 26 javascript ecmascript-6

安全代码new Set()可能如下所示:

let items = [];
for (let item of set)
  if (isBad(item))
    items.push(item);
for (let item of items)
  set.delete(item)
Run Code Online (Sandbox Code Playgroud)

我可以简化代码:

for (let item of set)
  if (isBad(item))
    set.delete(item);
Run Code Online (Sandbox Code Playgroud)

安全代码new Map()可能如下所示:

let keys = [];
for (let [key, val] of map)
  if (isBadKey(key) || isBadValue(val))
    keys.push(key);
for (let key of keys)
  map.delete(key)
Run Code Online (Sandbox Code Playgroud)

我可以简化代码:

for (let [key, val] of map)
  if (isBadJey(key) || isBadValue(val))
    map.delete(key)
Run Code Online (Sandbox Code Playgroud)

Ber*_*rgi 28

是的,你可以简化,这是完全安全的.

  • 集合和地图始终按插入顺序迭代
  • 删除项目不会影响任何迭代器的位置 - 您可以直观地清空未被更改的集合的形状.
  • 因此:将不会迭代已删除但尚未迭代的元素
  • 已经迭代并被删除的元素(如在您的情况下)将不会影响除其他迭代/查找之外的任何内容.
  • 在迭代期间添加(并且不是集合的一部分)的元素将始终被迭代

从最后一点开始,唯一危险的事情就是这样

const s = new Set([1]);
for (let x of s) {
    s.delete(x);
    s.add(1);
}
Run Code Online (Sandbox Code Playgroud)

但不是因为未定义的行为或内存累积,而是因为无限循环.

  • 您应该说“是的,它很安全”,而不仅仅是“是”,因为标题以“这很危险吗……”开头。 (6认同)
  • 您能否添加一个指向参考文档的链接来证实您的陈述? (4认同)

Kir*_*ril 8

我会说是的,这是安全的.当您使用for ... of引擎盖迭代Set/Map时,循环将通过@@ iterator.和迭代器与工作.next()只:所以没有指标,也不管是什么当前位置之前.只有一个下一个元素很重要.

因此,除非在当前迭代器位置"之前"删除元素,否则可以安全地执行此操作.

  • @Bergi,根据规范-[是](https://tc39.github.io/ecma262/#sec-set.prototype.delete):`对作为条目元素的每个e重复一次,-如此循环在所有条目上。但是,当然,只有按照规范实施。 (3认同)
  • 规范只定义了所需的行为,而不是如何实现它.实现可以 - 例如 - 通过将其实现为具有插入顺序链接集条目的哈希集来实现定义的行为,从而实现分摊的O(1)查找,同时保持可预测的顺序. (2认同)