Cloning objects is one of the most commonly used operations in the JavaScript universe. In this article, we will dive into different types of cloning that exist in JavaScript (Node.js and Browser environment). We will also discuss the most efficient ways to shallow and deep clone objects in JavaScript.
📝 There are many blog posts, articles, and stack overflow threads that exist on this topic already. This article is my attempt to put the collective knowledge of the internet into one composed summary that is easy to follow and reference.
Let’s dive in 🏄♀️
Native deep cloning
Native deep cloning is known as “structured cloning” in Node.js. This feature is not available in the browser. Structured cloning supports an additional set of data types along with the ones that are supported by JSON. Here’s a list of additional data types it supports. Here’s an example of native deep cloning below:
const v8 = require('v8');
const structuredClone = obj => {
return v8.deserialize(v8.serialize(obj));
};
let sampleObject = {
hello: 'hello',
a: 'worlds',
nested: {
first: 'first object value'
}
};
let cloned = structuredClone(sampleObject);
JSON.parse/stringify — cloning with data loss
Good ol’ JOSN.stringify() is the most used method for cloning an object when you don’t care about data loss or shallow clone is sufficient for your use case. Here’s a simple example
let some_obj = {
name: "Shadid Haque",
age: 26,
items: ["health portion", "bow", "arrow"]
}
let copy = JSON.parse(JSON.stringify(some_obj));
console.log(copy)
Applying JSON.strigify() causes data loss when the object to be copied has complex data or functions nested. Here’s an example where data loss happens on JSON.strigify().
let objA = {
name: "Super Man",
attack: () => {
console.log("damage++");
}
};
const copy = JSON.parse(JSON.stringify(objA));
console.log(copy);
Spread Operations — shallow clone
Spread operation is the easiest way to clone a object in ES6. Data loss happens on this method as well. However, since this is native to ES6 it is more performant than JSON.strigify().
Checkout the benchmark here.
Here’s an example of cloning with spread operator
let A1 = {a: "2"};
let A3 = {...A1}; // Spread Syntax
Object.assign()
Object.assign() is an ES6 method that allows shallow cloning simmilar to spread operation.
let obj = {a: "2"};
let objCopy = Object.assign({}, obj);
Deep Cloning with lodash library
If you are looking for a reliable deep cloning method and don’t mind using a third party library then lodash might just be the solution you are looking for.
const cloneDeep = require('lodash.clonedeep');
let objects = [{ 'Hensen': 1 }, { 'Jon': 2 }];
let deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
Deep cloning with custom function
Finally, we can roll out our own function for deep copying an object. I found the following code snippet from stack overflow and I have been using it in my projects.
function clone(obj) {
if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
return obj;
if (obj instanceof Date)
let temp = new obj.constructor();
else
let temp = obj.constructor();
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = clone(obj[key]);
delete obj['isActiveClone'];
}
}
return temp;
}
If you are concerned about performance of various cloning functions I highly suggest you take a look at this following thread. I hope this article was helpul. That’s all for today 🙂, until next time
Top comments (1)
Native deep cloning is available in the browser. You just have to hack your way to it. The below pseudo-code gives the general idea... It might work but was just typed out here so maybe has typos ? 🤷♂️ (You can also use window.postMessage if you're on an ancient browser without MessageChannel support)