Search code examples
javascriptarraysloopsfor-loopjavascript-objects

Why is this for loop adding more nested objects than anticipated?


I was answering a question on here and I figured out how to do it using map() and the spread (...) operator, but I wanted to write it in more of a imperative way. I'll show you (1) what I've written, (2) what I expected to be the outcome, and then (3) the actual outcome.

(1) What I've written:

    const arrayOfObjects = [
        { var1: 1, var2: 2 },
        { var1: 3, var2: 4 },
        { var1: 5, var2: 6 },
        { var1: 7, var2: 8 }
    ]
    
    const newArray = []
    
    const length = arrayOfObjects.length
    
    for (let i = 0; i < length; i++) {
        if (i < (length - 1)) {
            newArray.push(arrayOfObjects[i])
            newArray[i].child = arrayOfObjects[i+1]
        } else {
            newArray.push(arrayOfObjects[i])
        }
    }
    
    console.log(newArray)

(2) So the expected outcome is this:

[ { var1: 1,
    var2: 2,
    child: { var1: 3, var2: 4 } },
  { var1: 3,
    var2: 4,
    child: { var1: 5, var2: 6 } },
  { var1: 5, var2: 6, child: { var1: 7, var2: 8 } },
  { var1: 7, var2: 8 } ]

(3) But the actual outcome is this:

[ { var1: 1,
    var2: 2,
    child: { var1: 3, var2: 4, child: [Object] } },
  { var1: 3,
    var2: 4,
    child: { var1: 5, var2: 6, child: [Object] } },
  { var1: 5, var2: 6, child: { var1: 7, var2: 8 } },
  { var1: 7, var2: 8 } ]

And if you were to inspect the first index of the new array, console.log(newArray[0]) you'll see that it's added a child object all the way down:

{ var1: 1,
  var2: 2,
  child: 
   { var1: 3,
     var2: 4,
     child: { var1: 5, var2: 6, child: [Object] } } }

I feel like I'm missing something very obvious, but I can't for the life of me figure it out! Thanks in advance :)


Solution

  • You need to do this

    Object are assigned by reference not by value.so in order to assign value you need to create a copy of it and than assign it.

     newArray[i].child = Object.assign({},arrayOfObjects[i+1])
    

    So here Object.assign will create a copy of arrayOfObjects.so now when you assign it will be assigned by value.

    const arrayOfObjects = [
        { var1: 1, var2: 2 },
        { var1: 3, var2: 4 },
        { var1: 5, var2: 6 },
        { var1: 7, var2: 8 }
    ]
    
    const newArray = []
    
    const length = arrayOfObjects.length
    
    for (let i = 0; i < length; i++) {
        if (i < (length - 1)) {
            newArray.push(arrayOfObjects[i])
            newArray[i].child = Object.assign({},arrayOfObjects[i+1])
        } else {
            newArray.push(arrayOfObjects[i])
        }
    }
    
    console.log(newArray)

    There is one more way to do it using ... operator.

    const arrayOfObjects = [
        { var1: 1, var2: 2 },
        { var1: 3, var2: 4 },
        { var1: 5, var2: 6 },
        { var1: 7, var2: 8 }
    ]
    
    const newArray = []
    
    const length = arrayOfObjects.length
    
    for (let i = 0; i < length; i++) {
        if (i < (length - 1)) {
            newArray.push(arrayOfObjects[i])
            newArray[i].child = {...arrayOfObjects[i]};
        } else {
            newArray.push(arrayOfObjects[i])
        }
    }
    
    console.log(newArray)