Shallow Copy vs Deep Copy in JavaScript (Objects, Arrays, References)

MediumIntermediateJavascript
Preparing for interviews?

Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.

Quick Answer

A shallow copy duplicates only the top-level structure and keeps nested object references shared, while a deep copy recursively copies everything. Knowing the difference is critical to avoid accidental mutations in state management, React/Angular, and general JavaScript code.

Answer

The core idea

In JavaScript, objects and arrays are reference types. A “copy” can either:

  • Shallow copy: copy only the top-level container, but keep nested objects shared.
  • Deep copy: copy everything recursively, so no nested references are shared.

Most bugs around state mutation come from thinking you made a deep copy but actually making a shallow one.

Type

What gets copied

What stays shared

Mutation risk

Shallow copy

Only the first level

All nested objects/arrays/functions

High (mutating nested data affects original)

Deep copy

All levels recursively

Nothing (new references everywhere)

Low (copies are fully independent)

The real difference is reference sharing.

Shallow copy examples

Common ways to make shallow copies:

JAVASCRIPT
const original = {
  name: 'Alice',
  address: { city: 'Paris' }
};

// Shallow copies:
const a = { ...original };           // spread
const b = Object.assign({}, original);

// Top-level is new:
a !== original; // true

// Nested object is shared:
a.address === original.address; // true

// Mutating nested object affects both:
a.address.city = 'London';
console.log(original.address.city); // 'London'  ❗
                  

Deep copy examples

JAVASCRIPT
const original = {
  name: 'Alice',
  address: { city: 'Paris' }
};

// 1) structuredClone (modern, correct for most cases)
const deep1 = structuredClone(original);

// 2) JSON trick (limited!)
const deep2 = JSON.parse(JSON.stringify(original));

// Check:
deep1.address === original.address; // false

deep1.address.city = 'Rome';
console.log(original.address.city); // 'Paris' ✅
                  

Why JSON.stringify is dangerous

It silently breaks or loses:

  • undefined, Symbol, functions
  • Date, Map, Set, RegExp
  • Circular references (throws)

So it only works for plain data objects.

What about arrays?

Same rules apply. [...arr] and arr.slice() are shallow.

JAVASCRIPT
const arr = [{ x: 1 }, { x: 2 }];

const copy = [...arr]; // shallow

copy[0].x = 999;
console.log(arr[0].x); // 999 ❗
                  

Where this matters in real life

  • React / Angular / Redux / NgRx state updates
  • Undo/redo stacks
  • Caching snapshots
  • Any place you assume “old state” is immutable

A shallow copy of a nested state tree is not enough.

Performance reality check

  • Deep copying large objects is expensive.
  • In practice, you often do structural sharing: deep copy only the path you change, keep the rest shared (like Redux/Immer).

This is why libraries like Immer exist.

One-sentence answer

A shallow copy creates a new top-level object but reuses nested references, while a deep copy recursively duplicates everything so changes in one copy never affect the other.

Similar questions
Guides
20 / 61