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:
- Object Basics
- Different ways of cloning an object
- 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.
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) :-
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 .
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.
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) .
We can see that :
- getHobbies property (function) is deleted from dev2 .
- 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.
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 !