My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more
What is Deep Copy and Shallow Copy in JavaScript??

Photo by Andrew Neel on Unsplash

What is Deep Copy and Shallow Copy in JavaScript??

Ankur Gupta's photo
Ankur Gupta
·Jan 13, 2022·

5 min read

Before we go into what is shallow copy or deep copy. We need to have knowledge about data structures in JavaScript. So in JavaScript there are 2 types of datatypes i.e Primitive Data Types and Structural Data Types or non-primitive

  1. Primitive Data Types:

    • undefined
    • boolean
    • number
    • string
    • BigInt
    • Symbol
  2. Structural or non-primitive data types:

    • Object
    • Functions
    • Class

This prerequisite was essential for knowing shallow copy and deep copy, no let's start😊.

Shallow Copy

When a reference variable is copied into a new reference variable using the assignment operator, a shallow copy of the referenced object is created.

I know that's a pretty heavy defination😅. So let's try to make it simpler... So Shallow copy simply means when we copy the reference and not the value.

let obj1 = {a: "Ankur", b: "Priya"}
let obj2 = obj1; // Shallow Copy
obj2.a = "Priya"
console.log(obj1) // {a: "Priya", b: "Priya"}

Here we have Shallow copied the reference of obj1 into obj2. But you might be wondering that we simply assigned the value using the = operator than why it copied the reference and not value. So the answer is...

When we assign the value using = operator, For primitive data types the value get's copied but for non-primitive or structural data types the reference gets copied.

let obj1 = {a: "Ankur", b: "Priya"}
let obj2 = obj1; // Reference getting copied as it is non-primitive
obj2.a = "Priya"
console.log(obj1) // {a: "Priya", b: "Priya"}

Deep Copy

Unlike the shallow copy, deep copy makes a copy of all the members of the old object, allocates separate memory location for the new object and then assigns the copied members to the new object.

Again it is very complicated😂, no worries let's make it simpler. So in deep copy the value is copied and the entire new memory location is allocated to the variable.

let a = 20;
let b = a; // Value getting copied as it is primitive
b = 30;
console.log(b)//30

But than you might be wondering that how to deep copy structural data types🙄. So there are 3 ways to deep copy strutural data types...

  1. Using Object.assign method
  2. Using Spread operator
  3. Using JSON.parse and JSON.stringify methods

Using Object.assign method

let obj1 = {a: "Ankur", b: "Priya"}
let obj2 = Object.assign({}, obj1); //Deep Copy
obj2.a = "Priya";
console.log(obj1); //{a: 'Ankur', b: 'Priya'}

for reading more about Object.assign: Link

Using Spread operator

let obj1 = {a: "Ankur", b: "Priya"}
let obj2 = {...obj1} //Deep Copy
obj2.a = "Priya";
console.log(obj1); //{a: 'Ankur', b: 'Priya'}

for reading more about Spread operator: Link

But both of these methods are not safe as they only deep copy at top level anything that is nested is shallow copied. Let's understand with example..

let obj1 = {a: "Ankur", b: "Priya", c: {d: "Tanay", e: "Gaurav"}} // c is nested
let obj2 = {...obj1} //Deep Copy At top level
obj2.a = "Priya";// Property a and b is top level so deep copied
obj2.c.d = "Changed"; // Property d is nested inside c so it is shallow copied
console.log(obj1); //{a: 'Ankur', b: 'Priya', c: {d: 'Changed', e: 'Gaurav'}}

Here the properties like a and b are at the top level so they are deep copied but the nested property c is shallow copied. So on changing c it would have reflect both the objects.

Don't worry to overcome this there is a way😊..

Using JSON.parse and JSON.stringify

let obj1 = {a: "Ankur", b: "Priya", c: {d: "Tanay", e: "Gaurav"}} // c is nested
let obj2 = JSON.parse(JSON.stringify(obj1)) //Deep Copy At all levels
obj2.a = "Priya";// Property a and b is top level
obj2.c.d = "Changed"; // Property c is nested inside c so it is shallow copied
console.log(obj1); //{a: 'Ankur', b: 'Priya', c: {d: 'Tanay', e: 'Gaurav'}}

Here JSON.stringify converts the object contents into string and then JSON.parse parses it to create a new object. for reading more about JSON.parse: Link

for reading more about JSON.stringify: Link

So you might be thinking so this would be the go to method for deep copying the objects. But sadly that is not true😂😅. Let's see why Consider this code

const obj = {a : "Ankur", b: 2, c: {d: 3,  e: function(){
  console.log("Inside e")
}}}
const obj1 = JSON.parse(JSON.stringify(obj));
obj.c.d = "Tanay";
console.log(typeof obj1.c.e)  // undefined ????

See here we are getting undefined why??. Because JSON.stringify method converts the JS object into JSON string, so it also tries to convert the function e which then becomes undefined.

So Remember this method of deep copying would not work if your object has one of these things Dates, functions, undefined, Infinity, RegExpression, Maps, Sets, blobs, Filelists, Imagedatas and many more complex data types...

So what's the full proof solution???

  1. To use libraries like loadash, Randa etc.
  2. To implement your own utility function.

Using loadash:

var loadash = require("./loadash");
const obj = {a : "Ankur", b: 2, c: {d: 3,  e: function(){
  console.log("Inside e")
}}}
const obj1 = loadash.deepclone(obj);
obj.c.d = "Tanay";
console.log(typeof obj1.c.e)  // the entire function

Using Utility Function

const deepCopy = (obj) => {
  // if it is not object
  if (typeof obj !== "object" || obj == null) return obj;

  //Checking if we have to create a object or array
  const newObject = typeof obj === "object" ? {} : [];
  Object.keys(obj).map((key) => {
    const value = obj[key];
    newObject[key] = deepCopy(value); //Recursive Call
  });
  return newObject;
};
const obj1 = deepCopy(obj);
console.log(obj1);

Hope you learnt something from the blog, please give me some feedbacks in it😊😊