Search code examples
javascriptarraysiterationfor-of-loop

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


I know it works with Set, but I was under the impression that it would also work with Array. So I tried it in Chrome and was surprised that it didn't work:

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]

It didn't delete the 4.

So my question is, is iteration safety only supposed to work with Set and Map, but not Array?

(If this is the case, then other than the simple syntax, I don't see the benefit of using it over for(;;). I was under the impression this for..of was going to prevent bugs, even with Array, like it does with Set and Map)

Note, as a trick, I can do it by cloning the array (or reverse iteration):

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]


Solution

  • No, (as your example demonstrates) it's not safe to remove elements from an array while iterating it.

    The default array iterator stores the current index, and it does not update this index when you call splice on the array. It just continues at the same position, no matter what you did to the elements in the array. You can read the spec for ArrayIterator objects, they basically work like a for (var index=0; index<array.length; index++) yield array[index]; loop.