What is the most efficient way to perform a JavaScript deep copy of an object, and how can I ensure it's both effective and efficient?

I’ve used methods like JSON.parse(JSON.stringify(o)) for deep copying, but I’m concerned about its performance. I’ve also come across non-standard solutions like eval(uneval(o)) (which works in Firefox), but I’m looking for a more universally accepted and efficient approach. Are there any better options for deep cloning an object in JavaScript?

Hey, I’ve worked with a few different methods over the years, and one of the most efficient and modern ways I’ve found to do a JavaScript deep copy is using structuredClone. It’s natively supported in most modern browsers and handles most data types out of the box, including Maps, Sets, Dates, and even circular references.

const clonedObj = structuredClone(originalObj);

:brain: Why it works well:

  • It’s fast.
  • Built-in (so no extra libraries needed).
  • Handles complex objects like Maps and Sets, which can be a pain with other methods.

:wrench: Limitations:

  • The only real downside is that it’s not supported in very old browsers (IE or early versions of Edge), but as of 2024, this is pretty much a safe go-to for any modern browser.

I totally get the concern with performance, especially if you’re looking for a more universally accepted solution. For a robust and widely used approach, I recommend Lodash’s cloneDeep method. It’s a great alternative when you need deep cloning that’s consistent across browsers, and it covers more edge cases.

import cloneDeep from 'lodash/cloneDeep';

const clonedObj = cloneDeep(originalObj);

:hammer_and_wrench: Why it’s a favorite:

  • It works seamlessly across all browsers.
  • Handles tricky cases like functions, class instances, and circular references.
  • It’s highly maintained by the community, so you get both reliability and support.

:bulb: When to use it: If you’re already working with Lodash, it’s a no-brainer. If not, it’s definitely worth considering for its consistency and thorough handling of edge cases in a JavaScript deep copy.

If you’re more into learning or customizing things for your specific needs, writing your own deep copy function can be a good exercise. It’s simple but provides a lot of flexibility in how you want to handle the copying process.

function deepCopy(obj) {
  if (obj === null || typeof obj !== 'object') return obj;

  if (Array.isArray(obj)) {
    return obj.map(deepCopy);
  }

  const copy = {};
  for (let key in obj) {
    copy[key] = deepCopy(obj[key]);
  }
  return copy;
}

:mag: Why it’s cool:

  • It’s a great way to understand how deep copying works under the hood.
  • You can easily modify it to handle specific cases as you see fit.

:rotating_light: Watch out: This approach doesn’t handle circular references, special types like Date or Map, or prototype chains (it only works with pure objects). If you need these features, you might want to go with a library solution like Lodash or structuredClone.