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.
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.
Spread operator can be used to create deep copy of an object.
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 } }
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.
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);
Another way to do deep copy is to use following or write similar function, where we can recursively copy all properties.
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:
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