Deep and Shallow copy is a technique in which we copy arrays or objects so that they don't have the same reference in the memory. Why do we need deep or shallow copy? So we need it in pure functions where arguments should not get mutate. Let's get stared!
Shallow copy
Let's take one example to better understand shallow copy
const array1 = [1, 2, 3];
const array2 = array1;
array2.push(4)
console.log(array2); // [1,2,3,4]
console.log(array1); // [1,2,3,4]
In the above example we have defined array1
with [1,2,3]
and then we declared array2
and assigned array1
to it. Now we push 4
to array2
and console log it which gives us [1,2,3,4]
but when we console log array1
, it also have the same value as array2
. So we can see array1
got mutate because when we assigned array1
to array2
we actually pass reference to it, so array2
have same reference of array1
. If we do array1 === array2
we will get true. Any changes we do in array2 will reflect in array1, to solve this we use shallow copy
Let's make a shallow copy of array1 using spread operator
const array1 = [1,2,3];
const array2 = [...array1];
array2.push(4);
console.log(array2); // [1,2,3,4]
console.log(array1); // [1,2,3]
In the above example we used spread operator to copy elements of array1
to array2
, but you can also use Array.from
, Array.slice
for arrays and Object.assign()
to copy objects. Now if we repeat the process what we did in the first example we can see that changing array2
is not mutating array1
because the reference is not same. Now if we check array1 === array2
we will get false. Hence we solved the array mutation using spread operator. But there is a catch. If we had a nested array inside array1
and do any changes in nested part in array2
then it will reflect in array1
. Because spread operator only do shallow copy not deep copy. To resolve this issue we need to do deep copy.
Deep copy
To copy nested arrays or objects we use deep copy. The simple way to get deep copy is to use JSON.stringify
and JSON.parse
. Let's see with example
const team1 = {
lead: "Jhon",
backend: "Aron",
frontend: {a: "Jane", b: "Tony"}
}
const team2 = JSON.parse(JSON.stringify(team1));
team2.frontend.a = "Rhodey";
console.log(team1 === team2) // false
Here we have used JSON methods to get deep copy of nested objects. Let's see how to write our own deep copy function.
const deepCopy = (obj) => {
if (typeof obj !== "object" || obj === null) return obj;
const newObject = Array.isArray(obj) ? [] : {};
for (let key in obj) {
const value = obj[key];
newObject[key] = deepCopy(value);
}
return newObject;
};
Inside deepCopy
function we pass object that we need to deep copy. First we check the data type of object that is passed, if it's not object then we will return it else we check if the object we passed is array or not because type of array is also object. Then depending on is it array or object we have empty starter. Then we use for in
loop to loop over element. Then we use recursion and pass the value, if the value of data type is object whole process repeat else it is return and loop continues and at end we get our deep copy.
Summary
- Hence we saw what is shallow and deep copy
- Why we need
- Different ways to achieve it