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

时间:2016-03-11 12:23:06

标签: 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)

我可以将代码简化为:

for (let item of set)
  if (isBad(item))
    set.delete(item);

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)

我可以将代码简化为:

for (let [key, val] of map)
  if (isBadJey(key) || isBadValue(val))
    map.delete(key)

2 个答案:

答案 0 :(得分:23)

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

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

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

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

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

答案 1 :(得分:8)

我会说是的,这是安全的。当您使用引擎盖下的for ... of迭代Set / Map时,循环将经历@@iterator。并且Iterator仅与.next()一起操作:所以没有索引,也不管当前位置之前是什么。只有一个下一个元素很重要。

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