← Back to Home

Deep vs. Shallow Copy in JavaScript – How to Avoid Common Pitfalls

Nick Lukic  | 
Deep vs. Shallow Copy illustration

Introduction

When working with objects in JavaScript, making copies of data isn't always as simple as it seems. JavaScript has two types of copies: shallow and deep. Understanding the difference is essential, as each approach has different effects on your data and can lead to unexpected bugs if used incorrectly. Let's break down each type, see examples, and discuss when each one is appropriate.

What is a Shallow Copy?

A shallow copy creates a new object and copies over the top-level properties from the original object. But if those properties are references to other objects, the references themselves are copied, not the nested data. This means that both the original and copied objects share the same nested references, so changes in one affect the other.

Example of a Shallow Copy

Below is an example where modifying a property in the copied object also changes the original:

const original = {
    a: 1,
    b: {
        c: 2,
    },
};

const shallowCopy = { ...original };
shallowCopy.b.c = 3;

console.log(original.b.c); // 3 (changed!)
console.log(shallowCopy.b.c); // 3

In this example, we used the spread syntax (...) to make a shallow copy of original. However, because b is a nested object, shallowCopy still references the same b object. Modifying shallowCopy.b.c affects original.b.c as well.

Common Methods for Shallow Copying

You can create a shallow copy using these methods:

  • Object.assign()
  • Spread syntax (...) for objects and arrays
  • Array.slice() for arrays

Shallow copies are useful for simple or flat data structures but may lead to issues if you need independent copies of nested objects.

What is a Deep Copy?

A deep copy is an independent duplicate of the entire object structure, including all nested data. Changes in the copy do not affect the original, and vice versa. Deep copies are commonly used when working with complex or nested objects that shouldn't share references.

Example of a Deep Copy

Here's how a deep copy works, showing how changes in the copied object leave the original untouched:

const original = {
    a: 1,
    b: {
        c: 2,
    },
};

const deepCopy = structuredClone(original);
deepCopy.b.c = 3;

console.log(original.b.c); // 2 (unchanged!)
console.log(deepCopy.b.c); // 3

In this example, structuredClone() creates a deep copy, duplicating all nested levels. Modifying deepCopy.b.c doesn't affect original.b.c, making each object fully independent.

Methods for Deep Copying

Here are common ways to create deep copies in JavaScript:

  • structuredClone(): This native method provides deep copying and supports most types of data.
  • JSON.parse(JSON.stringify()): Works for JSON-safe data but excludes functions, undefined, Infinity, etc.
  • Lodash's _.cloneDeep(): For complex data types and when compatibility with different types is needed.

Each of these methods has pros and cons, but they all create deep copies, ensuring full independence between original and copy.

When to Use Shallow vs. Deep Copy

Shallow Copy: Use this for flat objects or arrays where shared references won't lead to issues. It's a faster method, so it's ideal for simple use cases.

Deep Copy: Use a deep copy for objects with nested data if you need full independence between the original and the copy. Deep copies are slightly more resource-intensive, but they're necessary for complex data structures that shouldn't interact.

Conclusion

Knowing when to use shallow or deep copying can make a big difference in avoiding unintended side effects in JavaScript. A simple rule of thumb is:

  • Use shallow copies for simpler data structures.
  • Use deep copies for complex data with nested objects where you need each instance to remain fully independent.

Mastering these techniques ensures that your data stays consistent and prevents common bugs. Screenshots of the code examples above can be inserted to visualize the differences in behavior and help you get a better grasp of this essential JavaScript concept.

Contact

Tell me what you're working on, what you would like help with, and I will reply to you as soon as possible.