Best Way To Clone Objects In JavaScript

In this article, you will learn about the best and easiest way to perform a shallow clone of objects in JavaScript. You will also learn how you can update, add or remove properties in place on the clone. Let's understand some basic keywords that we are going to use throughout this article.
 

What is Object?

 
In JavaScript an object is a collection of properties, and a property is an association between key and a value.
 
Let’s look through the properties and value of a plain JavaScript object.
 
Listed are some of the common characteristics for a literal to be known as object,
  • The keys of an object are the list of property names.
  • The values of an object are the list of property values.
  • The entries of an object are the list of pairs of property name and values.
Let’s consider the following object,
  1. const person = {  
  2.    name: 'John',  
  3.    city: 'Gotham'    
  4. };  
In the example given above, person is the name of the object which contains the properties keys are ['name', 'city'] and the values are ['John', 'Gotham']. And the entries are [['name', 'John'], ['city', 'Gotham']].
 

What is shallow clone?

 
A shallow copy or clone means that only the actual object gets copied. Shallow cloning does not copy nested objects.
 

Introduction

 
Just remember that JavaScript objects are mutable by nature and stored as a reference. So, when you assign the object to another variable, then you’re just assigning the memory address of the object to that variable. When we change anything in either of the object, it will reflect in the other. 
 
JavaScript provides 3 best ways to clone or copy objects,
  1. Using object spread
  2. Using object rest
  3. Using Object.assign() method

Cloning using object spread

 
This one is the simplest way to clone a plain JavaScipt object,
  1. const clone = {    
  2.    ...sampleObject    
  3. };    
Where sampleObject is the object which we want to copy, and clone is the shallow copy of object.
 
Let’s take an example of creating a shallow copy of the “person” object,
  1. const person = {    
  2.     name: 'John',  
  3.     city: 'Gotham'  
  4. };  
  5. const personClone = {    
  6.     ...person    
  7. };  
  8. console.log(personClone); // { name: 'John', city: 'Gotham' }    
Here, personClone is a cloned object of person, which means that it contains all the properties of the person that we declared.
 
Object spread: add or update clone props
 
One of the benefit of using object spread is that you can update or add new properties to the cloned object. 
 
Let’s clone the “person” object, but in this case we also want to update the name property with a different value and we also want to add a new property age in the object.
  1. const person = {    
  2.     name: 'John',  
  3.     city: 'Gotham'  
  4. };    
  5. const personClone = {    
  6.     ...person,    
  7.     name: 'John Wayne',  
  8.     age: 23    
  9. };    
  10. console.log(personClone);    
  11. // { name: 'John Wayne', city: 'Gotham', age: 23 }   
As you can see, in the console the value of the name property changed with a property named age added to the object.
 

Cloning using object rest 

 
Another way to shallow clone an object is by using the object rest operator,
  1. const {...clone } = object   
Let’s see an example for copying person object using rest operator,
  1. const person = {      
  2.     name: 'John',  
  3.     city: 'Gotham'  
  4. };  
  5. const { ...personClone  } = person;   
  6. console.log(personClone); // { name: 'John', city: 'Gotham' }    
As shown in the above example, after applying the rest operator const { …personClone } = person, the personClone variable contains a copy of person object. 
 
Object rest: skip cloned props
 
Object rest has an ability to skip certain properties when cloning.
 
For example, let’s create a clone of person object, but skip city property of the object while cloning,
  1. const person = {    
  2.     name: 'John',  
  3.     city: 'Gotham'  
  4. };    
  5.     
  6. const { city, ...personClone  } = person;    
  7. console.log(personClone); // { name: 'John' }    
Object rest: combining object spread and rest
 
Object spread has an ability to allow updating or adding new properties to the object, while object rest has an ability of skipping properties in the resulting clone object. 
 
Now let’s try to combine both into one statement to inherit all the benefits. 
 
Let’s clone the person object, where would add a new property age and skip the property city,
  1. const person = {    
  2.     name: 'John',  
  3.     city: 'Gotham'  
  4. };    
  5. const { city, ...personClone } = {    
  6.     ...person,  
  7.     age: 23    
  8. };    
  9. console.log(personClone); // { name: 'John', age: 23 }    

Cloning using object.assign()

 
Object.assign function lets you clone the same object,
  1. const clone = Object.assign({}, object);     
Let’s create a clone object of person object using Object.assign(),
  1. const person = {    
  2.     name: 'John',  
  3.     city: 'Gotham'  
  4. };    
  5.     
  6. const personClone = Object.assign({}, person);    
  7. console.log(personClone); // { name: 'John', city: 'Gotham' }    
Object.assign({ }, person) creates a copy of the person object by merging the second argument person into the first argument { } of the assign method.
 
Object.assign( ): add or update cloned props
 
Object.assign( ) also has an ability to add and update properties to the clone.
 
Let’s create copy of person object, but at the same time update name property’s value,
  1. const person = {    
  2.     name: 'John',  
  3.     city: 'Gotham'  
  4. };    
  5.     
  6. const personClone = Object.assign({}, person, { name: 'John Wayse' });  
  7. console.log(personClone); // { name: 'John Wayse', city: 'Gotham' }     
Object.assign({ }, person, { name: 'John Wayse' }) creates the object in 2 parts,
 
Step 1
 
The second argument is merged into the first argument { } of the assign method. This results in { name: 'John', city: 'Gotham' }.
 
Step 2
 
The third argument { name: 'John Wayse' } is merged into the result from the previous step that is the result of our second step, overwriting the property name which we already have in our third argument. So our final resulting object will be { name: 'John Wayse', city: 'Gotham' }.
 

Summary

 
In this article, I discussed about common characteristics of objects. After that we saw how we can clone objects using spread operator, rest operator and Object.assign() function. And we also discussed about update, add or remove properties in place on the clone with examples.