DEV Community

Cover image for The Most Efficient Ways to Clone objects in JavaScript
Shadid Haque
Shadid Haque

Posted on

The Most Efficient Ways to Clone objects in JavaScript

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);
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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

References

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types

https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript/5344074#5344074

https://www.npmjs.com/package/lodash.clonedeep

Discussion (2)

Collapse
coulson84 profile image
Joe Coulson

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)


function clone(toClone) {
  return new Promise((yay, nay) => {
    const { port1, port2 } = new MessageChannel();

    port1.onmessage = ({ data }) => yay(data);
    port2.postMessage(toClone);
  });
}

clone({a:1}).then(a => console.log(a));
Enter fullscreen mode Exit fullscreen mode
Collapse
lukeshiru profile image
LUKESHIRU

For actual deep cloning, I recommend klona, a tiny and performant util by lukeed.