Splicing a Javascript array from within the callback passed to forEach

One possibility would be to use the array.slice(0) function, which creates a copy (clone) of the array and thus the iteration is separated from the deletion.

Then the only change to the original approach using array.forEach would be to change it to array.slice(0).forEach and it will work:

array.slice(0).forEach(function(item) {
    if(item === "b") {
        array.splice(array.indexOf(item), 1);
    }
    alert(item)
});

After the forEach, the array will contain only a and c.

A jsFiddle demo can be found here.


Another possibility would be to use the array.reduceRight function to avoid the skip:

//iterate over all items in an array from right to left
//if the item is "b", remove it.

const array = ["a", "b", "c"];

array.reduceRight((_, item, i) => {
    if(item === "b") {
        array.splice(i, 1);
    }

});

console.log(array);

After the reduceRight, the array will contain only a and c.


Using Array.prototype.filter as in thefourtheye's answer is a good way to go, but this could also be done with a while loop. E.g.:

const array = ["a", "b", "c"];
let i = 0;

while (i < array.length) {
    const item = array[i];

    if (item === "b") {
        array.splice(i, 1);
    } else {
        i += 1;
    }

    console.log(item);
}

Lets see why JavaScript behaves like this. According to the ECMAScript standard specification for Array.prototype.forEach,

when you delete an element at index 1, the element at index 2 becomes the element at index 1 and index 2 doesn't exist for that object.

Now, JavaScript looks for element 2 in the object, which is not found, so it skips the function call.

That is why you see only a and b.


The actual way to do this, is to use Array.prototype.filter

var array = ["a", "b", "c"];

array = array.filter(function(currentChar) {
    console.log(currentChar);   // a, b, c on separate lines
    return currentChar !== "b";
});
console.log(array);             // [ 'a', 'c' ]