Different ways to do Shallow and Deep Copy in Javascript?

Different ways to do Shallow and Deep Copy in Javascript?

Introduction

Hi javascript enthusiast, hope you are doing good. When we learn any programming language we come across the term copy, this functionality is used to store value of one variable in another variable. Normally there are 2 ways to copy values one is copy the reference and second one is copy the value. In javascript copy the reference is called as shallow copy and copy the value is called as deep copy. Let's see how copy works for different type of datatypes.

1. Primitive Data Types

In the case of primitive data types there is no complexity involved in copying functionality. In this type of value copy happens in deep copy manner. So whenever we copy values from one variable to another, second variable does not keep reference to variable from which the value is copied. so if we change the value of second variable first variable value does not affect.
Let's see one example,

let a=10;
console.log(a); // 10
let b=a;
console.log(b); // 10
b=20;
console.log(a); // 10
console.log(b); // 20

In this example initially a is copied to b, so b get's only value of a not the reference so later we have changed value of b, Now b got new value but value of a remains unchanged. So we can say that deep copy operation happens while copying primitive datatypes .

2. Non-Primitive Data Types

In this kind of data types we see the concept of shallow copy and deep copy.
At first let's check how copy happens with = operator in Non-primitive datatypes,

const a=[ 1, 2, 3, 4 ];
console.log(a); // [ 1, 2, 3, 4 ]
const b=a; // copies along with reference
console.log(b); // [ 1, 2, 3, 4 ]
b[0]=5; // changes first values of both a and b
console.log(a); // [ 5, 2, 3, 4 ]

Here in this example, We can see the concept of shallow copy. In shallow copy value is copied along with the address, so whenever value of second variable changes value of variable from where it is copied also changes.
Here we checked for array, But if we try this for object also same operation happens. Let's see one example for object also,

const obj1={
   firstName: "Deekshith",
   lastName: "M D"
}
const obj2 = obj1;
obj2.firstName="deekshith";
console.log(obj1) // {firstName: 'deekshith', lastName: 'M D'}

Here when you copy obj1 to obj2 it copies obj1 along with its reference, So when we change value of obj2 value in obj1 also changes.

Till now we saw how copy happens with = operator, Now let's see some standard ways to copy primitive datatypes, mainly there are 3 way to do copy operation, they are

  1. Using Object.assign()
  2. Using spread (...) operator
  3. Using JSON.stringify() and JSON.parse()

1. Using Object.assign():

Object.assign() is used to create copy of one or more objects, It takes first parameter as empty object or any object to which the objects should be appended. It does deep copy on first level but when we use it for copying nested objects we end up with shallow copy. Let's see this with one example

const obj1 = {
  firstName: "Deekshith",
  lastName: "M D",
  address:{
      city:"Mangalore"
  }
};
const obj2 = Object.assign({}, obj1);

obj2.firstName = "deekshith";
obj2.address.city="Bangalore";

console.log(obj1); // { firstName: 'Deekshith', lastName: 'M D', address: {city: 'Bangalore'} }
console.log(obj2); // { firstName: 'deekshith', lastName: 'M D', address: {city: 'Bangalore'} }

We can see here at 1st level deep copy achieved but in next level i.e city changed in both objects.

2. Using spread (...) operator

Copy operation using spread operator works similar to Object.assign(). Spread operator also does deep copy at first level and when goes into nested object level it does shallow copy. Let's see one example for this,

const obj1 = {
  firstName: "Deekshith",
  lastName: "M D",
  address:{
      city:"Mangalore"
  }
};

const obj2 = { ...obj1 }

obj2.firstName = "deekshith";
obj2.address.city="Bangalore";

console.log(obj1); // { firstName: 'Deekshith', lastName: 'M D', address: {city: 'Bangalore'} }
console.log(obj2); // { firstName: 'deekshith', lastName: 'M D', address: {city: 'Bangalore'} }

We can see here thatfirstName changed in obj2 only, but city changed in both objects. So we can conclude that spread operator does deep copy at first level and shallow copy of nested level objects.

3. Using JSON.stringify() and JSON.parse()

We saw how we can copy objects using Object.assign() and spread operator, But both are ended up providing deep copy only at first level when we get into nested level it provides shallow copy only. So here is the solution to get perfect deep copy i.e by using JSON.stringify() and JSON.parse(). If we use this method to copy non-primitive datatypes then we can perform any operation on copied object without affecting source object. Let's check this by looking into one example,

const obj1 = {
  firstName: "Deekshith",
  lastName: "M D",
  address:{
      city:"Mangalore"
  }
};

const obj2 = JSON.parse(JSON.stringify(obj1))

obj2.firstName = "deekshith";
obj2.address.city="Bangalore";

console.log(obj1); // { firstName: 'Deekshith', lastName: 'M D', address: {city: 'Mangalore'} }
console.log(obj2); // { firstName: 'deekshith', lastName: 'M D', address: {city: 'Bangalore'} }

If we check here, we get deep copy at nested level also in first level firstName is changed that affected only obj2 and in nested level change city that also affected only to obj2, So we can say that it is possible to achieve perfect deep copy using SON.stringify() and JSON.parse().

This is about how copy operation happens in javascript.
I hope this blog helped you to understand the concept of Shallow copy and Deep copy.

Thank you

References

  1. https://www.freecodecamp.org/news/copying-stuff-in-javascript-how-to-differentiate-between-deep-and-shallow-copies-b6d8c1ef09cd/
  2. https://www.javascripttutorial.net/object/3-ways-to-copy-objects-in-javascript/