Shallow Copies vs. Deep Copies in JavaScript: When to Use Each

Shallow Copies vs. Deep Copies in JavaScript: When to Use Each

Table of contents

  • Introduction

  • Shallow copies

  • Deep copies

  • Spread syntax

  • Deep copying objects

    • JSON.stringify() and JSON.parse()

    • structuredClone()

  • Conclusion

Introduction

When copying objects in JavaScript, it is important to understand the difference between shallow and deep copies.
A shallow copy creates a new object that contains the same properties as the original object, but the values of those properties may still refer to the same memory locations as the original object.
On the other hand, A deep copy ,copies all the fields with dynamically allocated memory. That is, every value of the copied object gets a new memory locations rather than the original object.

But when should you opt for a shallow copy, and when is a deep copy more appropriate? The answer hinges on your specific needs:

  • Shallow copies are the choice when you want to create a new object that shares the same data as the original object, but you don't need to modify the original object. For example, you might use a shallow copy to create a new object to pass to a function as an argument.

  • Deep copies come into play when you need to create a new object that is completely independent of the original object. For example, you might use a deep copy to create a new object that you will be modifying, and you don't want those modifications to affect the original object

Spread syntax

The spread syntax (...) is a new feature in JavaScript that allows you to expand arrays and objects. When used with objects, the spread syntax only deep copies the top level data of an object. Nested objects are shallow copied, meaning that they will still refer to the same memory locations as the original object. This can be a problem if you need to create a completely independent copy of the object.

Example:

const oldObj = {
  a: { b: 10 },
  c: 20,
};

const newObj = { ...oldObj };

oldObj.a.b = 30; // This also changes the newObj.a.b value to 30, because they both refer to the same memory location.
oldObj.c = 40; // This changes the oldObj.c value, but the newObj.c value remains 20.

console.log(newObj);
// Output: { a: { b: 30 }, c: 20 }

In the above example, when we create the newObj object using the spread syntax, we are creating a shallow copy of the oldObj object. This means that the newObj object will have the same properties as the oldObj object, but the values of any nested objects will still refer to the same memory locations as the original object.

When we change the value of the b property on the oldObj object, the value of the b property on the newObj object also changes, because they both refer to the same memory location. However, when we change the value of the c property on the oldObj object, the value of the c property on the newObj object does not change, because the c property on the newObj object is referring to a new copy of the object.

Deep copying objects

If you need to create a deep copy of an object, you can use one of the following methods:

  • JSON.stringify() and JSON.parse()

The JSON.stringify() and JSON.parse() methods can be used to create a deep copy of an object. The JSON.stringify() method converts an object to a JSON string, and the JSON.parse() method converts a JSON string back to an object.

const oldObj = { a: { b: 10 } };
const newObj = JSON.parse(JSON.stringify(oldObj));

console.log(newObj);
// Output: { a: { b: 10 } }

oldObj.a.b = 20;

console.log(newObj);
// Output: { a: { b: 10 } }

As you can see, when we change the value of the b property on the oldObj object, the value of the b property on the newObj object does not change. This is because the JSON.parse() method creates a deep copy of the object, and the b property on the newObj object is referring to a new memory location.

  • structuredClone()

The structuredClone() method is a new method in JavaScript that creates a deep copy of an object. The structuredClone() method is similar to the JSON.stringify() and JSON.parse() methods, but it is more efficient and can handle a wider range of object types.

const oldObj = { a: { b: 10 } };
const newObj = structuredClone(oldObj);

console.log(newObj);
// Output: { a: { b: 10 } }

oldObj.a.b = 20;

console.log(newObj);
// Output: { a: { b: 10 } }

As you can see, when we change the value of the b property on the oldObj object, the value of the b property on the newObj object does not change. This is because the structuredClone() method creates a deep copy of the object, and the b property on the newObj object is referring to a new memory location.

Conclusion

The spread syntax (...) is a convenient way to create shallow copies of objects. However, if you need to create a deep copy of an object, you should use one of the following methods:

  • JSON.stringify() and JSON.parse()

  • structuredClone()

The structuredClone() method is the most efficient and robust way to create a deep copy of an object.

Let's connect: