2

When I run this code, all object of the array are the same.

var obj = {
     a: { b: 0 }
    }

    var arr = [];

    for(i = 0; i < 10; i++) {
    arr.push(obj);
    obj.a.b += 5;
    }

    for(i = 0; i < arr.length; i++) {
    document.writeln(arr[i].a.b);
    }

How can I send current values of the object to the array? Like:

[
  {"a": b: 5 },
  {"a": b: 10 },
  {"a": b: 15 },
...
]

jsfiddle

enter image description here


After Answered

I created a benchmark test for Object.assign vs JSON.stringify for the deep clone.

http://jsben.ch/64Cxe

akcoban
  • 953
  • 7
  • 14
  • 1
    move `obj.a.b += 5;` to the top of `console.log`'s as you did here – Artyom Amiryan Nov 21 '18 at 12:25
  • @ArtyomAmiryan It doesn't matter for my question. Please read again. – akcoban Nov 21 '18 at 12:27
  • 1
    You can use console.log(JSON.stringify(obj)); to console.log a snapshot of that object – naortor Nov 21 '18 at 12:29
  • arrays are passed by reference in javascript, and values, in the console, are evaluated **immediately** when you expand them (in case of objects in general, hence even arrays). You may use `JSON.parse(JSON.stringify(obj));` to properly get a "snapshot" of the object, by losing the reference to the original one (arrays are objects, in javascript). That said, simply push a **new copy** of the object to avoid reference issues, like this: https://jsfiddle.net/m4pqxo1d/4/ – briosheje Nov 21 '18 at 13:02
  • `Object.assign({}, obj)` is for shallow object copy - in your benchmark you use it for deep copy (which is not good because - for large object you will need to write a lot of code). On stack overflow you can find alternative apprach to object deep copy e.g here https://stackoverflow.com/q/122102/860099. – Kamil Kiełczewski Nov 21 '18 at 14:08

3 Answers3

2

obj is a reference to an object, so what you are really doing is pushing the same reference to an object over and over again.

You end up with an array of the same reference to an object. if you want an array of different objects, you need to make a copy of the object before pushing it, you can accomplish it by

arr.push({...obj})

or

arr.push(Object.assign({},obj})

naortor
  • 2,019
  • 12
  • 26
  • Don't think for only console.log. I updated my answer, can you check again? – akcoban Nov 21 '18 at 12:42
  • obj is a reference to an object, so you are always pushing the same reference to an object to the array, if you want to push different objects, you need to create different copies of it. `arr.push({...obj});` – naortor Nov 21 '18 at 12:44
  • by {...obj} you are creating a new copy of obj. you can also use `arr.push(Object.assign({},obj))` – naortor Nov 21 '18 at 12:45
  • Can you share jsfiddle for that? i tried but there's no difference. https://jsfiddle.net/d36cnmz9/ – akcoban Nov 21 '18 at 12:51
  • oh, it happens because you need to deep clone the object (property a is an object that all the 'new object' still keeps a reference to) – naortor Nov 21 '18 at 12:57
1

Chrome console don't show full object for console.log(obj); but only { a: {...} } - and when you click on "triangle" to show object content chrome console use actual object value.

StackOverflow snipped show full object content immediately on each iteration - but chrome only keep reference to object and look on him deeper only when user click on "triangle" in console.

You should make nested(deep) copy (popular way is for example JSON.parse(JSON.stringify(obj)) but you can find better ways on StackOverflow) of object at current loop iteration and give that deep copy to console.log(copyObj); . For example:

var obj = {
  a: {
    b: 0
  }
}

for (i = 0; i < 10; i++) {
  obj.a.b += 5;
  console.log('log obj.a.b = ' + obj.a.b);
  console.log( JSON.parse(JSON.stringify(obj)) );
}

After question update

The arr.push(obj) push only reference to the same object obj to array, use below code to add separate copy of obj (reference to copy to be precise) as new array element:

arr.push( JSON.parse(JSON.stringify(obj)) )
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
0

This has to do with value versus reference.

Stackoverflow turns the value of the object into a string before logging. When you then change the value of the object the string doesn't change.

The chrome logs do it a bit different, they log the actual value of the object by looking at a certain point in memory, when you then edit that object the log will also update because it still points to that part of the memory.

If you'd like to also turn it into a string you could use JSON.stringify(obj);

Remco
  • 58
  • 5