In this blog, we will be covering various scenarios of cloning objects.
Before moving ahead let’s first check what is cloning and its types.

What is Cloning

In real life, Cloning is the process of generating a genetically identical copy of a cell or an organism. Similarly, in the coding world cloning is a process of creating an exact copy of an existing object in the memory.

Types of Object Cloning

There are 2 types of clonings in JS: Shallow and Deep cloning, the main difference between the two lies in the memory reference, where one holds the same reference while later does not.

1. Shallow Cloning

A new object is created that has an exact copy of the values in the original object. If any of the fields of the original object holds references to other objects, then only references of those objects are copied into clone object, copy of those objects are not created. Which means any changes made to those objects through the clone object will be reflected in the original object or vice-versa. 

shallow-copying

2. Deep Cloning

Deep copy duplicate everything i.e. a new object is created that has an exact copy of the fields of the original object, even the fields containing other objects are copied fully without holding back any reference.

deep-clning

Example of Different Object

1. Simple Object

Let’s first start with a simple object containing few properties name and age. Then we will try cloning it with different methods like = operator, object.assign, etc and will see whether it is shallow or deep clone.

let obj = { name: 'Sachin', age: 30 };

Clone Using equal (=) operator

As we can see in the code above any change made to the cloned object also changes the original object, we can say = operator does a shallow copy.

Clone Using equal Object.assign()

Here we see that using Object.assign() the cloned object is deep cloned, as a change made to age does not change the original object.

Clone Using spread (…) operator

The spread operator here also shows an example of a deep clone as the original age is not affected.

Clone Using JSON stringify and parse

Here we are first converting the object into Json string using JSON.stringify() and then we are converting it back into object using JSON.parse(), and we see that it gives us a deep cloned object.

2. Nested Object

We saw the results for simple object and now let us try the same for the nested object.

let obj = {
   name: {
     fName: 'Sachin',
     lName: 'Bachhav'
   },
   age: 30
 };

Clone Using equal (=) operator

Similar to the previous result of equal operator, we see it making a shallow copy here for nested object.

Clone Using equal Object.assign()

As we can see a change in the cloned name.lName also changes the original name.lName, which proves that Object.assign makes a shallow copy for nested objects.

Clone Using spread (…) operator

We have seen spread operator performing deep copy with simple objects but here with complex objects it fails and makes a shallow copy as the original object lName gets changed.

Clone Using JSON stringify and parse

As we can see in above snippet lName of the original object does not change, this shows that this method of cloning is a deep clone.

3. Object with one or more array

Now let’s try something with arrays, so here we create an array of names inside the object and try to see object cloning with different approaches.

let obj = {
   name: {
     fName: 'Sachin',
     lName: 'Bachhav'
   },
   age: 30
 };

Clone Using equal (=) operator

Equal (=) operator works as expected and makes a shallow copy as we see a change in the array of the cloned object changes the array in the original object.

Clone Using equal Object.assign()

Once again Object.assign() fails to achieve deep clone and ends up getting a shallow cloned object.

Clone Using spread (…) operator

Same as Object.assign, spread operator fails to give us a deep cloned object and instead gets a shallow cloning.

Clone Using JSON stringify and parse

Unlike other methods which gave us a shallow copy with this example object, JSON stringify and parse gives us a deep cloned object, as we can see that the actual array i.e. [‘pizza’, ‘ice-cream’] does not change even after changing the array in cloned object’s array.

4. Complex Object

Thus far we have played with simple objects of various types containing primitive data types, objects, and array now let’s try to sum up all of these things into a single object itself and then we will play with different cloning methods and see the observation.

let obj = {
  name: {
    fName: 'Tony',
    lName: 'Stark',
    weaponNames: ['Lasers','Pulse Bolts','Energy Blade','Repulsor Rays']
  },
  age: 55,
  friends: [
    { name: 'Peter Parker', character: 'Spider Man' },
    { name: 'Bruce Banner', character: 'Hulk' },
  ]
};

Clone Using equal (=) operator

oh! you already guessed, that’s true we get a shallow copy of object once again using the equal (=) operator.

Clone Using equal Object.assign()

This is somewhat surprising, this time using Object.assign() we get partial deep or we can say partial shallow cloned object. If you notice, we changed the friends (objects in array) as well as name.weaponNames (array in object property ) of which “friends” is unaffected but “name.weaponNames” got changed.

Clone Using spread (…) operator

Spread operators behave exactly like the Object.assign() and we get to see a partial deep copy where the “friends” is unaffected but “name.weaponNames” got changed.

Clone Using JSON stringify and parse

Well, this will be of no surprise that this method is once again able to achieve the deep cloning of the object. As we can see we changed the friends (objects in array) as well as name.weaponNames (array in object property ) in the cloned object but the original remained same.

Summary

Equal (=)Object.assignspreadstringify &
parse
Simple ObjectShallowDeepDeepDeep
Nested ObjectShallowShallowShallowDeep
Object with arrayShallowShallowShallowDeep
Complex ObjectShallowPartial DeepPartial DeepDeep