javascriptarraysobjectforeach-object

JS forEach traverses the problem of modifying objects


Why does the first modification work (when I reassign properties of the object) but not the second (when I reassign the whole object)?

const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
]

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10   // modify success
    }
});

console.log(arr1);

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item = {id:6,value:6}  // modify fail
    }
});

console.log(arr1);
.as-console-wrapper { max-height: 100% !important; top: auto; }


Solution

  • Consider the example below:

    We create an object and assign it to variable foo and then we assign foo to bar. So, now both foo and bar refer to the same object, as illustrated in the diagram below.

    let foo = { id: 1, val: "foo" };
    let bar = foo;
    

    enter image description here

    Next let's change the val field of the object i.e. assigned to bar. We notice that the change is reflected by both the variables foo and bar and this is because both the variables refer to the same object.

    let foo = {id: 1,val: "foo"};
    let bar = foo;
    bar.val = "bar";
    console.log(foo, bar);

    enter image description here

    Next we assign a new object to bar. Notice this doesn't effect the object that foo refers to, bar is simply now referring to a different object.

    let foo = { id: 1, val: "foo" };
    let bar = foo;
    bar = { id: 1, val: "bar" };
    console.log(foo, bar);

    enter image description here

    Let's relate this to the forEach example in your question. So, in every iteration of the forEach loop, the item argument in the callback function points to an object from the array and when you change a field from this item argument it changes the object in the array but when you assign item to a new object it does nothing to the object stored in the array.

    If you want to replace the entire object with a new one, there are several approaches you could take, two of which are mentioned below:

    1. Finding the index where the object is stored and replacing it with a new object.

    const arr = [{ id: 1, value: 1 }, { id: 2, value: 2 }, { id: 3, value: 3 }, { id: 4, value: 4 }, { id: 5, value: 5 }];
    
    const index = arr.findIndex((obj) => obj.id === 3);
    if (index !== -1) {
      arr[index] = { id: 6, value: 6 };
    }
    
    console.log(arr);

    1. Another really common approach is to map over the array and create a new array with that one object replaced.

    const arr = [{ id: 1, value: 1 }, { id: 2, value: 2 }, { id: 3, value: 3 }, { id: 4, value: 4 }, { id: 5, value: 5 }];
    
    const newArr = arr.map((obj) => (obj.id === 3 ? { id: 6, value: 6 } : obj));
    
    console.log(newArr);