Sign in
Log inSign up
Shallow and Deep Copy In JavaScript

Shallow and Deep Copy In JavaScript

Read it , to know why shallow copy is called shallow and deep copy is deep

Ashish Kumar's photo
Ashish Kumar
·Jan 15, 2022·

6 min read

So In JavaScript we have majorly two type of Data types i.e, Primitive Data type
( number, string , boolean , undefined and null) and Composite Data type(Array and Object).

1). For Primitive Data Types

When we try to copy the Primitive Data type, we don't have to bother about this deep and shallow copy concepts , because here for every copy a new data type will be created in the stack memory. Now as for every copy we have a new data type with the same content , changes in the prior one will affect the newly created data type.

Here we copy the variables by just using assignment(" = ") operator.

For example --

let a = "Ashish"
let b = a; // copying "a" content into "b"
a = "Ujjwal"
console.log(a) // Ujjwal
console.log(b) //Ashish

So here , initially we have defined variable "a" which is equal to "Ashish". Now when we try to copy it into "b" , a new "Ashish" will get created and got bounded with "b". Now when we redefine the value of "a" and change it to "Ujjwal" the previous binding of "a" with "Ashish" will be broked and it will get bounded with "Ujjwal".

That the reason when we try to see "a" and "b" values after these operator , it will show "Ujjwal" and "Ashish" respectively.

2). For Composite Data types.

These are also known as Reference Data Types. I have used both Reference and Composite Keyword
Here we can copy our variable by three ways--

(i) Using Assignment operator which we used for the Primitive Data Type Case.
Note - This is not Shallow Copy .
(ii) Using Shallow Copy( Spread Operator and Object.assign())
(iii) Deep Copy

2.1 Using Assignment Operator .

When we try to copy using assignment operator only the new name will be created but both the old name and new name will refer to the same reference.
The changes done in the old one will affect the content of new one.
For example -

let profile_1 = { name : "Ashish" , hobby : [ "Singing", "Listing_Music" ] }
let profile_2 = profile_1
profile_1.name = "Prashant"
console.log(profile_1.name) // Prashant
console.log(profile_2.name) // Prashnat

Here , Initially a object will be created in the heap memory , the reference of that object will get bounded with "profile_1" variable. Now when we try to copy that object in "profile_2" , JavaScript engine won't create a new object , it just bind the same old reference of the object with "profile_2".
Now when we change the "name" property of the object associated with "profile_1" , it will also get reflected in the object associated with "profile_2", as both had got attached with the same object .
So when we see the output of profile_1.name and profile_2.name, both will show "Prashant"

2.2 Using Shallow Copy

So finally we come to our topic :) :)
We can shallow copy a reference type variable using spread operator {...} and Object.assign() method.
What happens here is when we try to copy one object to an another object, a new reference will be created for the new object, But the internal content of the new object will be simply copied using assignment operator "=" from the old Object i.e, for Primitive data type they will be totally different from the old one, But for the Reference data type , the reference will be same.
Confusing Right???
Let Understand it Using Example

let profile_1 = { name : "Ashish" , hobby : [ "Singing", "Listing_Music" ,"Visiting New Place"] }
let profile_2 = Object.assign({}, profile_1)
profile_2.name = "Prashant"
profile_2.hobby[0] = "Playing Cricket"
console.log(profile_1) 
console.log(profile_2)

Output will be --

{
  name: 'Ashish',
  hobby: [ 'Playing Cricket', 'Listing_Music', 'Visiting New Place' ]
}
{
  name: 'Prashant',
  hobby: [ 'Playing Cricket', 'Listing_Music', 'Visiting New Place' ]
}

So what happens here is , when we copied the "profile_1" Object to "profile_2" , a new object got created in the heap memory and the content of the new object will be copied from the old one but here for the Reference data type JavaScript engine won't create a new copy , what it does is that it just store the same reference. So here the "hobby" property of both object i.e, "profile_1" and "profile_2" will point to the same array . But "name" property of both will be different.

That's why when we changes the "name" property of the second object , it didn't change the "name" property of the first object, because they are different, Whereas when we do some changes in the "hobby" , that change got reflected to the first object also.

So, That the Reason it is called Shallow , because here we copied the Object in a Shallow way.

2.3 Using Deep Copy

In simple terms deep copy means copying an array or an object in such a way that any changes to the first object will not get reflected into the second object.
So what happens here is, even if there will be any the Composite data type variable present in the object a separate new copy ( Reference ) will be created .
We can Deep Copy a object using a trick of JSON,i.e, JSON.parse(JSON.stringify())
Keep in mind that it is costly operation , because it is not memory effective .

let profile_1 = { name : "Ashish" , hobby : [ "Singing", "Listing_Music" ,"Visiting New Place"] }
let profile_2 = JSON.parse(JSON.stringify(profile_1));
profile_2.name = "Prashant"
profile_2.hobby[0] = "Playing Cricket"
console.log(profile_1) 
console.log(profile_2)

Output will be

{
  name: 'Ashish',
  hobby: [ 'Singing', 'Listing_Music', 'Visiting New Place' ]
}
{
  name: 'Prashant',
  hobby: [ 'Playing Cricket', 'Listing_Music', 'Visiting New Place' ]
}

Here we can notice that changing the "hobby" property of "profile_2" does not affect the "hobby" property of "profile_1" , because here both are different array and they have stored different reference.
Now in the interview, it may happen that Interviewer will not be happy if you will use that JSON trick to create the Deep Copy. He may ask you to code some function which will deep copy an object.
I have come up with a recursive function which will create a deep copy of an object.

Here i have created a function which will recursively create shallow copy for every object it encounters and then it again check for the children if any object is present there ,then again recursive function wil be called on that object.

function deep_clone(obj, ret = {}) {
  for (let key in obj) {
    if (typeof obj[key] == "object") {
      ret[key] = Object.assign({}, obj[key]);
      deep_clone(obj[key], ret[key]);
    }
  }
  return ret;
}
let profile_1 = {
  name: "Ashish",
  hobby: {
    first_hobby: "Singing",
    second_hobby: "Listing_Music",
    third_hobby: "Visiting New Place",
  },
};
let profile_2 = deep_clone(profile_1);
profile_2.name = "Prashant";
profile_2.hobby.first_hobby = "Playing Cricket";
console.log(profile_1);
console.log(profile_2);

Output will be --

{
  name: 'Ashish',
  hobby: {
    first_hobby: 'Singing',
    second_hobby: 'Listing_Music',
    third_hobby: 'Visiting New Place'
  }
}
{
  name: 'Prashant',
  hobby: {
    first_hobby: 'Playing Cricket',
    second_hobby: 'Listing_Music',
    third_hobby: 'Visiting New Place'
  }
}

So we can say that here deep means we will copy the entire object deeply.