Techcookies

Deep copy in JavaScript

JavaScript | Mon Dec 25 2023 | 3 min read

What is Deep copy

To understand deep copy we should understand shallow copy first.

Shallow copy is a technique in which we creates a duplicate of the original object or array but retain the reference from the original object.

So if you change property of one property in the original object it'll get reflected in another object as well.

So it may leads to scenarios where you will end up having unwanted updated values or may get errors if you are using some framework where immutability is the core principal.

js
const marks = {"Student1": 39, "Student2": 68, "Student3": {Math: 80, English: 90}};
const marksCopy = {...marks};
console.log("marks", marks);
console.log("marksCopy", marksCopy);
//Output
//marks { Student1: 39, Student2: 68, Student3: { Math: 80, English: 90 } }
//marksCopy { Student1: 39, Student2: 68, Student3: { Math: 80, English: 90 } }

marksCopy.Student2 = 78;
marksCopy.Student3.English = 58;
marksCopy.Student3.Math = 95;
console.log("marks", marks);
console.log("marksCopy", marksCopy);

//Output
//marks { Student1: 39, Student2: 68, Student3: { Math: 95, English: 58 } }
//marksCopy { Student1: 39, Student2: 78, Student3: { Math: 95, English: 58 } }

In the above code, we have created one object marks and created a copy marksCopy using spread operator, spread operator is a great way to create a copy without copying refrence but it works for first/top level properties only.

So when we are change the property marksCopy.Student2 it doesn't get reflected in the original object marks.Student2.

But as we have used spread operator, sencond level properties Student3.Math or Student3.English is getting changed in original object as well.

Deep copy is a technique where we recursively copy values of proprties without retaining its parent/original object reference.
Unfortunately, JavaScript doesn't have any in-build method yet for deep copy.

How we can do Deep copy in JavaScript

Option 1

Spread operator can be used to create deep copy of an object.

js
const marks = {"Student1": 39, "Student2": 68, "Student3": {Math: 80, English: 90}};
const marksCopy = {...marks, Student3: {...marks.Student3} };
marksCopy.Student3.English = 58;
marksCopy.Student3.Math = 95;
console.log("marks", marks);
console.log("marksCopy", marksCopy);
//Output
//marks { Student1: 39, Student2: 68, Student3: { Math: 80, English: 90 } }
//marksCopy { Student1: 39, Student2: 68, Student3: { Math: 95, English: 58 } }

Option 2

It provides a quick solution, in order to deep-copy an object, we first convert it to a JSON string and parse that JSON string.

js
const DeepCopy = (original) => {
  return JSON.parse(JSON.stringify(original));
};

const marksCopy = DeepCopy(marks);
marksCopy.Student3.English = 58;
marksCopy.Student3.Math = 95;
console.log("marks", marks);
console.log("marksCopy", marksCopy);

Option 3

Another way to do deep copy is to use following or write similar function, where we can recursively copy all properties.

js
const DeepCopy = (originalObject)=>{
    if(Array.isArray(originalObject )){
        const result = [];
        for(const [index, value] of originalObject.entries()){
            result[index] = DeepCopy(value);
        }
        return result;
    } else if(originalObject && typeof originalObject === 'object'){
        const result = [];
        for(const [key, value] of Object.entries(originalObject)){
            result[key] = DeepCopy(value);
        }
        return result;
    } else{
        return originalObject;
    }
}

const marksCopy = DeepCopy(marks);
marksCopy.Student3.English = 58;
marksCopy.Student3.Math = 95;
console.log("marks", marks);
console.log("marksCopy", marksCopy);

//Output
//marks { Student1: 39, Student2: 68, Student3: { Math: 80, English: 90 } }
//marksCopy [ Student1: 39, Student2: 68, Student3: [ Math: 95, English: 58 ] ]

More consice version of the code:

js
const DeepCopy=(originalObject) => {
    if (Array.isArray(originalObject)) {
      return original.map(elem => DeepCopy(elem));
    } else if (typeof originalObject === 'object' && originalObject !== null) {
      return Object.fromEntries(
        Object.entries(originalObject)
          .map(([k, v]) => [k, DeepCopy(v)]));
    } else {
      return originalObject;
    }
  }

Refrence: https://exploringjs.com/deep-js/ch_copying-objects-and-arrays.html#deep-copying-in-javascript