45

I want to know is there a difference between

Object.assign({}, obj)

and

JSON.parse(JSON.stringify(obj))

for deep cloning of an object? Can anyone explain if they have any idea?

Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127
Ram
  • 501
  • 1
  • 6
  • 11
  • `Object.assign` doesn't deepcopy, it ["copies the values of all enumerable own properties from one or more source objects to a target object."](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) – Ilja Everilä Jan 25 '17 at 09:21
  • Here in chrome console var obj1={"d":22,"k":33} var obj2 = Object.assign({},obj1) obj2 Object {d: 22, k: 33} obj2.k=44 obj1 Object {d: 22, k: 33}... Here Obj1 did not change so its means it is deep copy right ? – Ram Jan 25 '17 at 09:42
  • No, it is a shallow copy. You are mutating the own properties of the copy. Try creating an object of objects, making a copy, and then mutating the "pointed to" objects. – Ilja Everilä Jan 25 '17 at 09:52

1 Answers1

76

The difference is that

Object.assign({}, obj)

creates a shallow copy, not deep, while

JSON.parse(JSON.stringify(obj))

serializes the object as a JSON string and then deserializes it, effectively creating a deep copy. It should be noted that this method can only "deep copy" plain old data, not complex objects and their prototype.

A shallow copy is just fine, if all of your properties point to primitive values, or if you have no intention to mutate objects referenced by the copy. If you do, the changes will be visible in both the original and the shallow copy, because they both reference the same object:

> let a = { k: { h: 1 } };
> let b = Object.assign({}, a);
> b.k.h = 2;
> a
{ k: { h: 2 } }
> b
{ k: { h: 2 } }

You of course can mutate the copy itself without it having any effect on the original:

> b.j = 4
> b.k = { new: 'object' }
> a
{ k: { h: 2 } }
> b
{ k: { new: 'object' }, j: 4 }

The serialize-deserialize trick on the other hand creates a deep copy where everything is created from scratch:

> let c = JSON.parse(JSON.stringify(b));
> c
{ k: { h: 2 } }
> c.k.h = 3
> c
{ k: { h: 3 } }
> a
{ k: { h: 2 } }
> b
{ k: { h: 2 } }

Another way to inspect the identities is using strict equality:

> let a = { k: { h: 1 } };
> let b = Object.assign({}, a);
> a.k === b.k  // both point to the same object
true
> let c = JSON.parse(JSON.stringify(b));
> c.k === b.k  // different objects
false
Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127
  • 1
    What a nice explanation!! – himanshupareek66 Jan 30 '20 at 06:13
  • 1
    I'm not sure if you've mentioned it somewhere in your answer as I just had a quick look, but JSON.parse(JSON.stringify(obj)) method doesn't copy methods of the object. So this is important. Of course it works great for plain objects (`{ key: value, }`). Check this answer for a full deep copy: https://stackoverflow.com/a/43753414/9868445 – aderchox Mar 05 '22 at 09:17
  • Making copies of objects with methods as attributes sounds like a source for some interesting pain. First thing that comes to mind are things like react components of old with bound functions as attributes. Even if you copy the function reference over, it is still bound to the original instance. – Ilja Everilä Mar 05 '22 at 15:09