Understanding Shallow and Deep copy in JavaScript Objects

Understanding Shallow and Deep copy in JavaScript Objects

How different types of object cloning works in JS ?

Hello Readers , hope you all are doing good . Today we're going to talk about objects in JavaScript and different ways to clone an object . This discussion will help us in understanding shallow and deep copy mechanisms as well . We will follow the below path in our journey:

  1. Object Basics
  2. Different ways of cloning an object
  3. Shallow Copy Vs Deep Copy

Object Basics

If you are a JS enthusiast , you might have heard this

Everything in JavaScript is an object

Let's rephrase the above sentence to - Nearly everything in JS is an object , except the primitives i.e null , undefined , strings, numbers, boolean, and symbols. MDN says -

JavaScript is designed on a simple object-based paradigm. An object is a collection of properties, and a property is an association between a name (or key) and a value. A property's value can be a function, in which case the property is known as a method.

Functions are first-class objects in JS because they can store properties , methods etc just like any other object . Function objects can be called and this ability differentiates it from other objects.

Object Representation (Example) -

const dev1 = {
            "name" : "Deep",
            "age" : 24,
            "role" : "Software Engineer",
            "skills" : {
                        "primary": "Frontend",
                        "secondary" : "DevOps"  
             },
             "getHobbies" : function() { 
                                      return [ 'Singing' , 'Travelling' , 'Reading'] 
                                      } 
}

We can also check and prove that array , functions etc are objects by using __proto__ and Prototype chaining (you can learn more about this here)

Different Ways of cloning an object

Cloning of an object A results in a new object B , which either points to same referenced object (same memory) as A , or a different copy altogether. There are multiple options available for cloning an object -

  • Using assign operator ( = )
  • Using spread operator { ... }
  • Using Object.assign()
  • Using JSON.parse(JSON.stringify())
  • Using lodash library

Shallow Copy vs Deep Copy

Now , let's try to understand the object cloning by considering the below example :

Suppose we have an object dev1 with properties - name and role . If we clone this object using = operator , we will get a copy of dev1 (let's say dev2) . Try to assign a different value to the name property of dev2 , and log both dev1 and dev2 in console.

image.png

This is knows as Shallow Copy , as dev2 is referencing the same memory address as dev1 , = is not creating a new object.

In order to create a new object , we can use either the spread operator { ... } or Object.assign() method. Let's see how it works (we'll be cloning dev1 and create 2 new objects dev3 and dev4) :-

image.png

You might've noticed the difference , change in value of a property in dev3/dev4 doesn't change the value of the property in dev1.

But there's a gotcha. If there's a nested object and the value of nested property is changed in dev3 (cloned object) , the change would get reflected in dev1 (original object) as well . So the above methods can be termed as Partial Deep Cloning strategies .

image.png

So we changed the nested property primary in dev2 object but it changed the value of primary in the original object as well.

In order to get a Deep copy / clone of a nested object , we can use JSON.parse(JSON.stringify()) method. Let's check the same example , but with JSON.parse() strategy.

image.png

Now we have got a perfect deeply cloned object , and these are the methods which developers use in the vast majority of the scenarios.

Let's talk about lodash now . Lodash is a JavaScript library which provides utility functions for common programming tasks based on functional paradigm. But why do we need lodash for deep cloning when we already have JSON.parse(JSON.stringify()) ? Let's find out.

Suppose our object has a property getHobbies , and the value of this property is a function (which returns an array of hobbies) . The object also has a joiningDate property , and the value of this property is a Date object. If we try to deeply clone this object using JSON.parse() , we will notice that it doesn't work on functions (it gets deleted from the new object) and date (data type is different than original object) .

image.png

We can see that :

  1. getHobbies property (function) is deleted from dev2 .
  2. Date type of joiningDate in dev2 is string , but it should be an object (as in dev1).

To solve the above issue , cloneDeep utility method from lodash library can be used to create a deep clone.

image.png

So we installed lodash library from npm using npm/yarn and used cloneDeep utility to clone dev1 object. Unlike JSON.parse() , it works on functions and date objects as well (see above example).

The End

Hope you've enjoyed reading this blog. Today we learned about Objects in JavaScript (basics) , different ways to clone an object , and the difference between shallow copy and deep copy .

Thank you for reading !