在使用for..of进行迭代时删除Set中的元素是否安全?

Den*_*ret 26 javascript iterator set ecmascript-6

它是指定的,你可以在一个实例删除任何元素Set,同时采用迭代for..of

  • 你不会在元素上多次迭代
  • 除了你删除的元素之外,你不会错过迭代开始时集合中的任何其他元素

Ben*_*aum 28

是的,在迭代时添加元素并删除元素是完全没问题的.这个用例被考虑并在JavaScript 2015(ES6)中得到支持.它将使其保持一致状态.请注意,这也适用于迭代forEach.

直观:

设置迭代算法基本上看起来像这样:

Set position to 0
While position < calculateLength() // note it's calculated on each iteration
    return the element at set.entryList[position]
Run Code Online (Sandbox Code Playgroud)

添加看起来像这样:

If element not in set
   Add element to the _end_ of the set
Run Code Online (Sandbox Code Playgroud)

因此它不会干扰现有的迭代 - 它们会迭代它.

删除看起来像这样:

Replace all elements with are equal to `element` with a special empty value
Run Code Online (Sandbox Code Playgroud)

用空值替换它而不是删除它确保它不会弄乱迭代器的位置.


正式地

加成

以下是规范的相关部分%SetIteratorPrototype%.next:

索引小于条目元素总数时重复.每次评估此方法时,必须重新确定元素的数量.

set迭代器继续逐个迭代这些条目.

来自Set.prototype.add:

将值附加为条目的最后一个元素.

这确保了在向列表添加元素时,它将在迭代完成之前进行迭代,因为它总是在条目列表中获得新的插槽.因此,这将符合规范要求.

至于删除:

将值为e的条目元素替换为值为空的元素.

用空元素替换它而不是删除它确保了现有迭代器的迭代顺序不会输出或顺序,它们将继续正确地迭代集合.

用代码

这是一个演示此功能的简短代码段

var set = new Set([1]);
for(let item of set){
   if(item < 10) set.add(item+1);
   console.log(item);
}
Run Code Online (Sandbox Code Playgroud)

其中记录了数字1到10.这是一个不用于...的版本,您今天可以在浏览器中运行:

var set = new Set([1]);
for (var _i = set[Symbol.iterator](), next; !(next = _i.next()).done;) {
   var item = next.value;
   if (item < 10) set.add(item + 1);
   document.body.innerHTML += " " + item;
}
Run Code Online (Sandbox Code Playgroud)

  • 更新:我收到了Brendan Eich的回复,显然有待观察的相关主题是https://esdiscuss.org/topic/set-iterators (3认同)