2

我知道它适用于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.

所以我的问题是,迭代安全是否只应该与Setand一起使用Map,而不是Array

(如果是这种情况,那么除了简单的语法之外,我看不到使用它的好处for(;;)。我的印象for..of是这将防止错误,即使使用Array,就像使用Setand一样Map

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

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]

4

3 回答 3

3

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

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

于 2019-06-21T14:57:01.403 回答
1

根据MDN

一般来说,除了当前正在访问的属性之外,最好不要在迭代期间从对象中添加、修改或删除属性。无法保证是否会访问添加的属性,是否会在修改之前或之后访问已修改的属性(当前属性除外),或者是否会在删除之前访问已删除的属性。

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

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

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

console.log(array)

于 2019-06-21T15:17:52.013 回答
1

那是因为当循环到3(index: 2) 时,数组删除了这个3值,4现在变成了 index:2。下一次迭代将转到 index: 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) 

于 2019-06-21T15:00:29.083 回答