Best Way To Clone Objects In JavaScript

Introduction

In this article, you will learn 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 essential keywords we will use throughout this article.

What is an Object?

In JavaScript, an object is a collection of properties; a property is an association between a key and a value.

Let's look through the properties and values of a plain JavaScript object.

Listed are some of the common characteristics for a literal to be known as an 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 names and values.

Let's consider the following object,

const person = {  
   name: 'John',  
   city: 'Gotham'    
};

In the example given above, a person is the name of the object which contains the properties keys ['name', 'city'], and the values are ['John', 'Gotham']. And the entries are [['name', 'John'], ['city', 'Gotham']].

What is a shallow clone in JavaScript?

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

Remember that JavaScript objects are mutable by nature and stored as a reference. So, when you assign the object to another variable, you're just assigning the object's memory address to that variable. When we change anything in either of the objects, 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,

const clone = {    
   ...sampleObject    
};

Where sampleObject is the object we want to copy, and clone is the shallow copy of an object.

Let's take an example of creating a shallow copy of the "person" object,

const person = {    
    name: 'John',  
    city: 'Gotham'  
};  
const personClone = {    
    ...person    
};  
console.log(personClone); // { name: 'John', city: 'Gotham' }    

Here, personClone is a cloned object of a person, which means it contains all the properties of the person we declared.

Object spread- add or update clone props

One of the benefits 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.

const person = {    
    name: 'John',  
    city: 'Gotham'  
};    
const personClone = {    
    ...person,    
    name: 'John Wayne',  
    age: 23    
};    
console.log(personClone);    
// { 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,

const {...clone } = object   

Let's see an example of copying a person's object using the rest operator,

const person = {      
    name: 'John',  
    city: 'Gotham'  
};  
const { ...personClone  } = person;   
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 the person object. 

Object rest- skip cloned props

Object rest can skip specific properties when cloning.

For example, let's create a clone of a person object but skip the city property of the object while cloning,

const person = {    
    name: 'John',  
    city: 'Gotham'  
};    
    
const { city, ...personClone  } = person;    
console.log(personClone); // { name: 'John' }   

Object rest- combining object spread and rest

Object spread can allow updating or adding new properties to the object, while object rest has the ability to skip properties in the resulting clone object. 

Now let's combine both into one statement to inherit all the benefits. 

Let's clone the person object, where we would add a new property age and skip the property city,

const person = {    
    name: 'John',  
    city: 'Gotham'  
};    
const { city, ...personClone } = {    
    ...person,  
    age: 23    
};    
console.log(personClone); // { name: 'John', age: 23 }    

Cloning using object.assign()

Object.assign function lets you clone the same object,

const clone = Object.assign({}, object);  

Let's create a clone object of a person object using Object.assign(),

const person = {    
    name: 'John',  
    city: 'Gotham'  
};    
    
const personClone = Object.assign({}, person);    
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( ) can also add and update the clone's properties.

Let's create a copy of the person object, but at the same time, update the name property's value,

const person = {    
    name: 'John',  
    city: 'Gotham'  
};    
    
const personClone = Object.assign({}, person, { name: 'John Wayse' });  
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, which results from our second step, overwriting the property name 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 common characteristics of objects. After that, we saw how to clone objects using the spread operator, rest operator, and Object.assign() function. And we also discussed updating, adding, or removing properties in place on the clone with examples.