Deep Copy vs Shallow copy

"Knowingly or unknowingly, since we all know JS in unpredictable, we end up modifying the existing data in JS objects / variables. To prevent this, we must ensure to safely copy the data."

By simply using the = (assignment) operator, we end up copying the addresses too in our new variables / objects, which results into data inconsistencies. If we copy data from an old to new & tend to modify only new then old also gets updated, which shouldn't be the case if we're not aligned to do that.

Copy is nothing but the replica of something.

Deep Copy -> All values of new variable are copied and are disconnected from the original variable, And the new object gets allocated a new / separate memory location. In this way, both the objects are independent.

Shallow Copy -> The copy gets created & both the new objects / variables are stored / referencing to the same memory location. Thus they're not independent.

// primitive data types 
// Number, string, boolean, null, undefined -> Naturally Immutability 
// Means can't be changed. They're tightly coupled to the variable they're
// assigned to.
// After copying, changes in the new variable won't cause any change in
// the old.

let a = 5;
let b = a;

console.log(" a before", a);
console.log(" b before", b);

b = 6;

console.log(" a after", a);
console.log(" b after", b);

let isApplied = true;
isNotApplied = isApplied;

isNotApplied = false;

console.log("isApplied", isApplied, "isNotApplied", isNotApplied);

Composite Data Types - Arrays & objects.

In JS, Arrays are nothing but Objects, so they both behave in the same way almost!

let arr = [1,2,3];

let newArr = arr; // craetes a shallow copy.

console.log("arr", arr);
console.log("newArr before", newArr);

newArr[1] = 5;

console.log("arr after", arr);
console.log("newArr after", newArr);

// To prevent shallow copy - 

newArr2 = [...arr]; //spread operator to deep copy 
newArr2[1] = 7;
console.log("arr after", arr);
console.log("newArr2 after", newArr2);

To prevent shallow copy - Spread operator, map, filter, reduce - as these 3 result in new [].

Case Of Nested Arrays -

let arr3 = [
  'Nik',
  'bakers',
  'delhi',
  arr4 =[
    'Hyd',
    'Del'
  ]
];

console.log("arr3", arr3);

let newArr3 = arr3;

console.log("newArr3", newArr3);
newArr3[2] = "Jammu";

console.log("arr3", arr3);
console.log("newArr3", newArr3);

Using the spread operator can prevent shallow copying -

let newArr3 = [...arr3];

console.log("newArr3", newArr3);
newArr3[2] = "Jammu";

console.log("arr3", arr3);
console.log("newArr3", newArr3);

Also, by using JSON.parse(JSON.stringify(arr)) can help to prevent shallow copy.

let newArr3 = JSON.parse(JSON.stringify(arr3));

console.log("newArr3", newArr3);
newArr3[2] = "Jammu";

console.log("arr3", arr3);
console.log("newArr3", newArr3);

Objects -

-> Assignment operator creates shallow copy.

let emp ={
    id : 32,
    name : 'Jack',
    dept : 'Sales'
};

let newEmp = emp;

newEmp.name = 'Ryan';

console.log("emp", emp);
console.log("new emp", newEmp);

-> Spread operator - Deep copy.


let newEmp = {...emp};

newEmp.name = 'Ryan';

console.log("emp", emp);
console.log("new emp", newEmp);

-> Object. assign - to deep copy, First parameter - always modified, second parameter - object to copy.

let newEmp = Object.assign({}, emp);

newEmp.name = 'Ryan';

console.log("emp", emp);
console.log("new emp", newEmp);

-> Nested objects -

  • Spread doesn't work much unless done in a different way.

      let person ={
          id : 32,
          name : 'Jack',
          dept : 'Sales',
          personal : {
              children : 2,
              Hobby : 'Music'
          }
      };
    
      let newPerson = {...person};
    
      newPerson.personal.children = 5;
    
      console.log("person", person);
      console.log("new person", newPerson);
    

    -> even after spreading, the nested object's properties are same in both new & old objects.

    -> Manually copying - Nested properties won't change in the old but it's not a good approach if we deal with dynamic data or it depends on the use case.

  •       let person ={
              id : 32,
              name : 'Jack',
              dept : 'Sales',
              personal : {
                  children : 2,
                  Hobby : 'Music'
              }
          };
    
          // let newPerson = {...person};
          // manually copying nested objects 
    
          let newPerson = {...person, personal : {...person.personal}};
    
          newPerson.personal.children = 5;
    
          console.log("person", person);
          console.log("new person", newPerson);
    

  • JSON.parse(JSON.stringify(object)) - If we're unaware about the nested structure.

      let newPerson = JSON.parse(JSON.stringify(person));
    
      newPerson.personal.children = 5;
    
      console.log("person", person);
      console.log("new person", newPerson);
    

Thank you so much for popping in here! That's all folks! For any Query / Suggestion/feedback, connect with me over LinkedIn. :)

0
Subscribe to my newsletter

Read articles from Niharika Gurnani directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Niharika Gurnani
Niharika Gurnani