Deep Copying Objects In JavaScript

When you try to copy objects in JavaScript with Object.assign or the spread operator, you might think you've avoided copying the items by reference.

And yes, this is true, but for only top-level properties of the object, if you try to update nested properties of an object, you'd notice that those properties in the source object are also updated, and subsequently any other object that was created from it.

Let's look at an example briefly.

const sourceObject = {
  question: "Here's a question",
  options: ["an", "array", "of", "options"],
  answer: 0
};

const objectCopy1 = {...sourceObject};

const objectCopy2 = Object.assign(sourceObject);

/* try updating an option in objectCopy1 */

objectCopy1.options[0] = "the"; 

console.log(sourceObject.options);
/* this logs -> ["the", "array", "of", "questions"] */

console.log(objectCopy2.options);
/* this logs -> ["the", "array", "of", "questions"] */

Why this behavior?

Object.assign and the spread operator do not really deep copy the items, only top level items are actually copied, the rest are copied by reference.

Is there a solution?

To the best of my knowledge, there's no inbuilt function in javascript to fix this issue, but here's a hack I use.

 const objectCopy1 = JSON.parse(JSON.stringify(objectSource));

This creates a string from the object and then creates an object from the string, in the process losing any reference to the original object.

JSON.parse(JSON.stringify()) is actually bad practice because JSON.stringify() can be very unpredictable in converting things like functions, symbols, or undefined, also the two functions put together can be very poorly performing especially with big objects, so use sparingly.

if you have a very big/complicated object, best to use lodash or this immutability-helper.

I hope this article helps you.

Let's connect on Twitter