What is the difference between Object.assign and JSON.parse(JSON.stringify(obj)) for deep cloning of an object?

Ram picture Ram · Jan 25, 2017 · Viewed 8k times · Source

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?

Answer

Ilja Everilä picture Ilja Everilä · Jan 25, 2017

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.

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