How to Deep Clone an Object in JavaScript
JavaScript is a language of objects. Almost everything is an object in JavaScript. Booleans, Numbers, Strings, Dates, Maths, Regex, Arrays, function, and objects themselves, all are objects. They are a collection of key-value pairs consisting of various attributes and methods. They are stored directly in memory and can be copied only by reference. A variable does not store the object but just a reference to that object in memory. So, when we try to copy an object variable, we end up creating an extra reference to the same object. This method is called shallow copy. It is not ideal as we do not want change in the original object to affect its clone. This creates the need for a method to deep clone the object. This tutorial teaches how to deep clone an object in JavaScript.
Shallow Copy vs Deep Copy
A shallow copy is a bitwise copy of the object. The new object created successfully copies the primitives like numbers, boolean, and strings but does not copy any references to objects. Only the reference addresses result in a pointer pointing to the same object. Any changes made in the original object are reflected in the shallow copy.
On the other hand, a deep copy does not copy just the address/reference to the original object but the whole object. The new object created does not have any dependency on the copied object. JavaScript provides us with various built-in methods to copy an object, but the shallow copy is the default behavior in most of them.
Shallow Copy Methods in JavaScript
We will briefly cover the shallow copy methods to make you aware of some of the wrong ways to deep copy.
Use the Spread Syntax to Shallow Clone an Object in JavaScript
We can clone an object by making a new object and then using the spread syntax to enumerate an object’s content inside it as its own. It seems like the right way, but it creates a shallow copy of the data.
const obj = {
a: 1,
b: {c: 2}
}
const clone = {...obj}; // creates a shallow copy
obj.b.c = 5;
console.log(clone.b.c); // outputs 5
In the above code, we use the spread
syntax to create a shallow copy of the object. We then modify one of the properties of the referenced object in the original object and show that property is modified in the cloned object.
Use the Object.assign()
To Shallow Clone an Object in JavaScript
The object.assign()
method assigns a shallow copy of the object to a new object variable. It takes two arguments: target and source. The target
is usually a pair of empty parenthesis used to represent the empty object in which to copy; it is an optional argument but passing it ensures that we do not end up changing the original object. The second argument is the object to be copied.
const obj = {
a: 1,
b: {c: 2}
}
const clone = Object.assign({}, obj); // creates a shallow copy
obj.b.c = 5;
console.log(clone.b.c); // outputs 5
In the above code, we use Object.assign()
to create a shallow copy of the object. We then modify one of the properties of the referenced object in the original object and show that property is modified in the cloned object.
Deep Copy Methods in JavaScript
Use JSON.parse()
and JSON.stringify()
to Deep Clone an Object in JavaScript
JSON.stringify()
is used to convert a JavaScript object into a JSON string and JSON.parse()
is used to convert a JSON string into JavaScript Object. We can wrap JSON.parse()
around JSON.stringify()
to first convert JavaScript object into JSON String and then parse it to get a copy of the object.
var user = {name: 'Harshit', age: 21, Profession: 'Software Engineer'};
let fakeDeepCopy = JSON.parse(JSON.stringify(user));
This method creates a deep copy but only for objects with no functions. It has problems with any circular dependencies like other referenced objects. The order of properties in the copied object may also differ from the original object. So, this method is a nice trick if we have a simple object with few primitive data types, but it is not recommended for the real world.
Use Native Deep Cloning to Deep Clone an Object in JavaScript
We can use the Node.js v8
module’s serialization algorithm to deep clone an object. Although it is limited to certain built-in data types, it preserves references within the cloned data. It allows us to copy several cyclic and recursive structures that were not supported by the JSON method.
const v8 = require('v8');
const structuredClone = obj => {
return v8.deserialize(v8.serialize(obj));
};
We deserialize and then serialize the object just like the JSON methods’ stringify and parse. But it preserves circular dependencies and is slightly better.
Use Lodash Library to Deep Clone an Object in JavaScript
Lodash library has functions for both shallow and deep copying, namely clone
and clonedeep
. It is a great library that allows us to import only the functions we need and not the complete library. The clonedeep
method works by recursively copying the value and then preserving all object inheritances, creating a true copy of the object.
const lodashClonedeep = require('lodash.clonedeep');
let obj = {a: 1, b: {c: 2}} let deepClone = lodashClonedeep(obj);
Here we load the clonedeep
function from lodash and use it to deep clone the object. It is a well-tested and maintained library, but it can only be used with Node.js and not Vanilla JavaScript.
Use the jQuery extend()
method to Deep Clone an Object in JavaScript
We can use jQuery’s .extend()
to shallow copy and deep copy an object. It is the most reliable deep cloning method with no data loss or corruption of data. Its major function is to merge two or more objects. But can be used to clone an object as well. It takes the following arguments: [deep]
, target
, object1 ..... objectN
.
[deep]
: It is an optional argument. Its only allowed value is true. If it is passed in the function, then the function creates a deep copy of the object. Otherwise, it forms a shallow copy.target
: The object to be extended. It will receive all the merged objects.object1, ..., objectN
: These are the objects to be merged/cloned into a new object.
let obj = {a: 1, b: {c: 2}} let shallowClone =
$.extend({}, obj); // creates a shallow copy
let deepClone = $.extend(true, {}, obj); // creates a deep copy
A more obvious solution can be just iterating through every property of the source object and replicating them into a new object. All the methods discussed above are compatible with all the major browsers.
Harshit Jindal has done his Bachelors in Computer Science Engineering(2021) from DTU. He has always been a problem solver and now turned that into his profession. Currently working at M365 Cloud Security team(Torus) on Cloud Security Services and Datacenter Buildout Automation.
LinkedIn