在 JavaScript 中使用 for..of 迭代时从数组中删除元素应该是安全的吗?

Is it supposed to be safe to remove elements from an array while iterating with for..of in JavaScript?

我知道它适用于 Set,但我的印象是它也适用于 Array。所以我在 Chrome 中尝试了它,但很惊讶它不起作用:

const array = [1,2,3,4,5,6]

for (const item of array) {
    if (item === 3 || item === 4) {
        array.splice(array.indexOf(item), 1);
    }
}

console.log(array) // [1,2,4,5,6]

它没有删除 4

所以我的问题是,迭代安全是否只适用于 SetMap,而不适用于 Array

(如果是这种情况,那么除了简单的语法之外,我看不出使用它比 for(;;) 有什么好处。我的印象是这个 for..of 会防止错误,即使使用 Array,就像使用 SetMap)

一样

注意,作为一个技巧,我可以通过克隆数组(或反向迭代)来做到这一点:

const array = [1,2,3,4,5,6]

for (const item of Array.from(array)) {
    if (item === 3 || item === 4) {
        array.splice(array.indexOf(item), 1);
    }
}

console.log(array) // [1,2,5,6]

不,(如您的示例所示)在迭代数组时从数组中删除元素是不安全的。

默认数组迭代器存储当前索引,当您在数组上调用 splice 时它不会更新此索引。无论您对数组中的元素做了什么,它都会在同一位置继续。您可以阅读 spec for ArrayIterator objects,它们基本上像 for (var index=0; index<array.length; index++) yield array[index]; 循环一样工作。

那是因为当循环到 3(索引:2)时,数组删除了 3 值,4 现在变成了 index:2。 下一次迭代将转到索引:3,即 5.

您也可以这样做:

const array = [1,2,3,4,5,6]
for (var i=0;i<array.length;i++) {
    if (array[i] === 3 || array[i] === 4) {
        array.splice(array.indexOf(array[i]), 1);
        --i;
    }
}

console.log(array) 

根据MDN

In general, it is best not to add, modify, or remove properties from the object during iteration, other than the property currently being visited. There is no guarantee whether an added property will be visited, whether a modified property (other than the current one) will be visited before or after it is modified, or whether a deleted property will be visited before it is deleted.

或者,您可以试试这个演示使用filter()

const array = [1, 2, 3, 4, 5, 6]

for (const item of [3, 4]) {
  array.splice(array.indexOf(item), 1);
}

console.log(array)