How to Clone Object in JavaScript

JavaScript objects are key-value pairs that allow you to store complex data in a compact manner. They are commonly used by today’s web developers to store various information such as user details, states, etc. since they can be easily converted into JSON and vice versa. Often, web developers need to copy a JavaScript object for some reason or the other. It can be tricky to clone object in JavaScript since you cannot use equality ‘=’ operator for this purpose, the way you do it with plain variables. In this article, we will learn several different ways to clone JavaScript objects.

Why Clone JavaScript Object

JavaScript objects are collections of key-value pairs where each value can be a simple data such as strings or integers, or complex data such as another JS object itself. Here is an example of a JavaScript Object.

var user = {
name: 'John',
age: 15,
city: 'NYC'
}

If you want to clone JavaScript object, people most likely use an equality operator for it. Let us see what happens when you do this.

var new_user=user;
console.log(new_user); // {name: 'John', age: 15, city: 'NYC'}

So far so good. Now let us update the name key’s value in new object. Then we display the content of both user and new_user objects.

new_user.name='Jane';
console.log(new_user); // {name: 'Jane', age: 15, city: 'NYC'}
console.log(user); // {name: 'Jane', age: 15, city: 'NYC'}

You will find that although you changed the name key’s value of only new_user object, it has also changed the corresponding value in user object. How did this happen? This is because the new_user is not a separate copy of user object but simply a new reference to it. So new_user and user point to the same object.

But we want new_user to be a different object such that when we update it, those changes must not affect user object. This is why equality operator does not work when you are trying to clone JavaScript objects. This is the problem we will solve in this article.

Shallow Clone vs Deep Clone

Before we learn the different ways to copy an object in JavaScript, it is essential to understand that there are two types of cloning possible in JavaScript – shallow and deep.

Shallow Cloning

In this type of cloning, the cloned object is a separate object, different from the original one. It has a different reference. However, if any of its properties are themselves JavaScript objects, then they will continue to reference those properties in the original object. In other words, only the top level properties are clones but the inner objects are the same for both objects. So if you make changes to any of the top-level properties in cloned object, they will not affect the original object. But if you make changes to any of the properties that are JS objects, they will affect those properties in original object also. Confusing? Don’t worry. We will see this with detailed examples below.

Deep Cloning

In this case, the cloned object is entirely different from the original one, with its properties as well as inner objects. Both of them are independent. So if you make changes to one of them, it will not affect the other one in any way. We will see this with the examples below.

How to Clone Object in JavaScript

There are mainly 4 different ways to clone objects in JavaScript.

1. Using Spread Operator

The spread operator (…) is one of the easiest ways to clone objects in JavaScript. It creates a new object reference. Here is its syntax.

cloned_object = {...original_object}

Here is an example to use spread operator. Let us say you want to clone the following JS object.

var user = {
name: 'John',
age: 15,
city: 'NYC',
marks:{english:50,maths:49}
}

Here is how to clone above object with spread operator and display the values of cloned object.

new_user = {...user};
console.log(new_user); // { name: 'John', age: 15, city: 'NYC',marks:{english:50,maths:49} }

You will see that the cloned object contains same properties as the original object. But, please note, it is only a shallow copy and not a deep copy.

Let us change the name property of new object and see if it changes the name property in original object also.

new_user.name='Jane';
console.log(new_user); // { name: 'Jane', age: 15, city: 'NYC',marks:{english:50,maths:49} }
console.log(user); // { name: 'John', age: 15, city: 'NYC',marks:{english:50,maths:49} }

As you can see, the changes made to one of the non-object properties in cloned object do not affect the original object.

But if you change the inner object marks, it will also affect the original object. Let us change the value of english property of marks object.

new_user.marks.english=45

console.log(new_user);
console.log(user);

You will see the following output indicating that the marks.english value has changed in both objects.

{
name: 'Jane',
age: 15,
city: 'NYC',
marks: { english: 45, maths: 49 }
}
{
name: 'John',
age: 15,
city: 'NYC',
marks: { english: 45, maths: 49 }
}

Spread operator can also be used to merge two or more arrays and objects, as shown below. Here is an example to combine two objects into a new object, and to combine two arrays into a new array.

object2 = {...object1, ...object2};
array3 = {...array1, ...array2};

2. Using Object.Assign

You can also create a shallow copy of object using Object.assign() function. You can input two or more objects as input to this function and it will return a new object which is a combination of properties of input objects.

Here is the syntax to clone an object using assign() function.

cloned_object = Object.assign({}, original_object);

Here is an example to clone user object using Object.assign() function.

var user = {
name: 'John',
age: 15,
city: 'NYC',
marks:{english:50,maths:49}
};

new_user = Object.assign({},user);
console.log(new_user); // { name: 'John', age: 15, city: 'NYC', marks: { english: 50, maths: 49 }}

In this case also, you get a shallow copy. If you change the name property of new_user, it will not affect the original object.

new_user.name='Jane';
console.log(user); // { name: 'John', age: 15, city: 'NYC', marks: { english: 50, maths: 49 }}
console.log(new_user); // { name: 'Jane', age: 15, city: 'NYC', marks: { english: 50, maths: 49 }}

But if you try to change the properties of inner object, they will impact both the cloned object as well as original object. This is because the inner object marks of new_user object still points to marks in original object.

new_user.marks.english=45

console.log(new_user); // { name: 'John', age: 15, city: 'NYC', marks: { english: 45, maths: 49 }}
console.log(user); // { name: 'John', age: 15, city: 'NYC', marks: { english: 45, maths: 49 }}

3. Using JSON

Both the above solutions give you a shallow copy. If you want to completely create a separate copy of JavaScript object, then you need to use a combination of JSON.parse() and JSON.stringify() functions. It will create a deep copy of your object where each property has a separate existence. Here is its syntax.

cloned_object = JSON.parse(JSON.stringify(original_object))

In this case, first we need to use JSON.stringify() function to convert the JavaScript object to JSON string.

json_user = JSON.stringify(user);
console.log(json_user); //{"name":"John","age":15,"city":"NYC","marks":{"english":50,"maths":49}}

Then we call JSON.parse() on this JSON string to create a JavaScript object from it. In this case, you will get a new object completely different from the original one.

new_user = JSON.parse(json_user);
console.log(new_user); // { name: 'John', age: 15, city: 'NYC', marks: { english: 45, maths: 49 }}

You can combine both JSON.stringify() and JSON.parse() functions into a single statement as shown below.

new_user = JSON.parse(JSON.stringify(user));

Let us try modifying the name property of new_user and see if it changes original object.

new_user.name='Jane';
console.log(new_user); // { name: 'Jane', age: 15, city: 'NYC', marks: { english: 45, maths: 49 }}
console.log(user); // { name: 'John', age: 15, city: 'NYC', marks: { english: 45, maths: 49 }}

You will see that the original object remains unchanged. Now let us change the inner property of cloned object.

new_user.marks.english= 45;
console.log(new_user);
console.log(user);

You will see the following output indicating that the original object remains unchanged. This proves that new_user is a deep copy of user object.

{
name: 'John',
age: 15,
city: 'NYC',
marks: { english: 45, maths: 49 }
}
{
name: 'John',
age: 15,
city: 'NYC',
marks: { english: 50, maths: 49 }
}

4. Using Loops

This is the regular way of looping through the original object and copying its each property to the new object. For this, we first create a new blank object.

new_user = {};

Then we loop through the original object, and one by one, copy its properties to the new object.

for (let prop in user) {
if (user.hasOwnProperty(prop)) {
new_user[prop] = user[prop];
}
}

console.log(new_user); // {name: 'John', age: 15, city: 'NYC', marks: { english: 50, maths: 49 }}

This will create a shallow copy. Let us change the marks.english property in new_user and see if it also changes the corresponding value in user object.

new_user.marks.english = 45
console.log(user); // {name: 'John', age: 15, city: 'NYC', marks: { english: 45, maths: 49 }}

console.log(new_user); // {name: 'John', age: 15, city: 'NYC', marks: { english: 45, maths: 49 }}

As you can see, changing inner object property in cloned object also changes the original object.

Conclusion

In this article, we have learnt several different ways to clone JavaScript objects. Among them, using spread operator and object.assign() function are the most convenient ways to clone JavaScript objects. But they both create shallow clones. If you want to do a deep clone, then you need to use JSON.parse() function. In this case, the original object needs to be JSON-ready. All these solutions clone JS object completely. Also, they are fast and scalable. However, if you only want to clone a specific part of your JS object, then you need to use the good old fashioned loop, where you individually clone each property. In this case, the performance will be slower than other methods due to the loop, but you can pick and choose which properties you want to clone. You can choose any of the above methods, depending on your requirements and tradeoffs therein.

Also read:

How to Detect Browser in JavaScript
How to Check if Element is Hidden in jQuery
How to Access Correct This Inside Callback

Leave a Reply

Your email address will not be published. Required fields are marked *