wonderful world
wonderful world

Reputation: 11599

'Object.assign' mutates state in deeper levels

I have a sample JSBin code at http://jsbin.com/givolafala/edit?html,js,console,output

var oldObject = { name: 'John', address: { city: 'new york'}};

var newObject = Object.assign({}, oldObject);

console.log(oldObject);
console.log(newObject);

newObject.name = 'Mathew';
newObject.address.city = 'los angeles';

console.log(oldObject);
console.log(newObject);

In this example, I'm changing the name which is at the top level from John to Mathew. The Object.assign returns the new state with the new name Mathew. The oldObject keeps its previous value John.

If I change any value in any level other than the root, it does not work. In the example I change the city to los angeles, and you will notice that the newObject and the oldObject have the same city los angeles. So the oldObject state is mutated.

Is this a bug?

Upvotes: 2

Views: 227

Answers (2)

Jakub Matczak
Jakub Matczak

Reputation: 15696

This is not a bug, this is called reference. There's a difference between how primitive values and objects (references to objectes actually) behaves.

var oldObject = { name: 'John', address: { city: 'new york'}};

oldObject consist of:

  • name which is a string value (primitive)
  • addres which is an object, so oldObject really has a reference to address object

Now:

var newObject = Object.assign({}, oldObject);

After copying newObject also has name value and address reference

newObject.name = 'Mathew';

Here you change a value of newObject's property.

newObject.address.city = 'los angeles';

But here you change a property of an object that newObject references. But this reference is also in oldObject so this will change oldObject too.

Basically both newObject and oldObject have a reference to same same address object.

What you expected to achieve is called deep copy.

Upvotes: 5

Jai
Jai

Reputation: 74738

I guess the description of Object.assign() says everything:

The Object.assign() method only copies enumerable and own properties from a source object to a target object.
It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters.

Therefore it assigns properties versus just copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters. For copying property definitions, including their enumerability, into prototypes Object.getOwnPropertyDescriptor() and Object.defineProperty() should be used instead.

Upvotes: 2

Related Questions