Shallow vs Deep Copy in JavaScript

Before diving into the topic, let's explore how Javascript handles assignments on primitive and reference variables.

Examples of Primitive data types are:

  • Numbers

  • String

  • Boolean

  • Null

  • Undefined

  • Symbols

Primitive data types do not have methods. Javascript converts Primitive string to string object so it is possible to use string object methods.

When we declare primitive data type in javascript, it is stored in stack and they are of value type which means each variable has its value and when we copy the value of a primitive data type then a real copy occurs.

Let's see what happens when we assign a variable to another or we copy the data of one variable to another.

let variable1 = 5;
let variable2 = variable1;
variable2 = 10;
console.log("varibale1:- " + variable1);
console.log("varibale2:-" + variable2);
// variable1:- 5
//variable2:- 10

Here both variable data are independent so one doesn't affect another but it is not the case with objects and arrays.

Let's see the case with reference data type:

Examples of Reference data types are:

  • Objects

  • Functions

  • Arrays

  • Dates

  • Another type of object...

Reference data types are dynamic and most of them are considered objects.

Let's see what happens in memory when we assign an object to another object.

let object = {
  Name: "Suraj Gaire",
  address: "Kathmandu",
};

let anotherObject = object;
anotherObject.address = "Lalitpur";

console.log(object);
console.log(anotherObject);

// object:- { Name: 'Suraj Gaire', address: 'Lalitpur' }
// anotherObject:- { Name: 'Suraj Gaire', address: 'Lalitpur' }

Here, we can see that when we modify the assigned object, the source data likewise modifies, which is known as a shallow copy.

Now we have some basic understanding of primitive and reference data types and how they are assigned in memory, Let's understand shallow and deep copy.

Shallow Copy

A shallow copy of an object is a copy whose properties share the same references as those of the source object from which the copy was made.

The following considerations must be made while implementing shallow copy:

  • Re-assigning top-level properties of the copy does not affect the source object.

  • Re-assigning nested object properties of the copy does affect the source object.

Let's analyze an example to better grasp these points:

let numbers = [
  1,
  2,
  3,
  {
    negativeNumbers: [-1, -2, -3],
  },
];

let copiedNumbers = [...numbers];
copiedNumbers[1] = 0;
copiedNumbers[3].negativeNumbers = [-1, -2, -3, -4];
console.log(numbers);
console.log(copiedNumbers);
// Output
// [ 1, 2, 3, { negativeNumbers: [ -1, -2, -3, -4 ] } ]
// [ 1, 0, 3, { negativeNumbers: [ -1, -2, -3, -4 ] } ]

Since numbers 1, 2, and 3 in this example are on the same level, changes to these numbers do not affect the source; however, since negativeNumbers is a nested object property, changes to those properties also affect the source.

The exact same thing applies when dealing with objects.

Deep Copy

A deep copy of an object is a copy whose properties do not share the same references as those of the source object from which the copy was made.In this method when we change either the source or the copy,we assure that we are not causing change to the other object to change to.

We can make a deep copy by using JSON.Stringfy to convert the object to JSON string,and then JSON.Parse to convert string back into a completely new javascript object.

Enough of this chit chat,let's see an example to analyze deep copy to grasp the concept.

let numbers = [
  1,
  2,
  3,
  {
    negativeNumbers: [-1, -2, -3],
  },
];
let copiedNumbers = JSON.parse(JSON.stringify(numbers));
copiedNumbers[1] = 0;
copiedNumbers[3].negativeNumbers = [-1, -2, -3, -4];
console.log(numbers);
console.log(copiedNumbers);
//Output:
//[ 1, 2, 3, { negativeNumbers: [ -1, -2, -3 ] } ]
//[ 1, 0, 3, { negativeNumbers: [ -1, -2, -3, -4 ] } ]

Above example is simple enough to be serialize but many javascript object are not serialized at all like functions,symbols,object that represent HTML elements in HTML DOM API,recursive data and many others in which case deep copy will fail.We can use lodash cloneDeep Method for deep copy to serialize our data.

It is to keep in mind shallow copy and deep copy are used while working with nested objects only.

You can use either of them according to your requirement.