Engrain by ByteRush

JS.06.03 Junior· 9 minCore — asked often

Shallow vs deep copy: why changing a copy changed the original

Spread and Object.assign copy only the top level. Learn reference semantics, what structuredClone can and cannot copy, and why a JSON round-trip loses data.

Comes up in: JavaScript, Coding

Learn#

Pooja builds an “edit order” screen. She copies the order with { ...order }, lets the user change a quantity, and clicks Cancel. The original order still shows the new quantity. Cancel did not cancel.

Variables hold objects by reference: they point to the object; they are not the object. Copying a variable copies the pointer.

Spread { ...obj }, [...arr] and Object.assign make a shallow copy: a new outer object whose properties still point to the same nested objects.

A deep copy copies nested objects too. structuredClone(value) does that using the structured clone algorithm. It handles Date, Map, Set, typed arrays and even cycles. It cannot copy functions, DOM nodes or class prototypes — class instances come back as plain objects.

The old trick, JSON.parse(JSON.stringify(x)), loses more: dates become strings, undefined and functions vanish, Map and Set become {}, and cycles throw.

const order = { id: 1, items: [{ sku: "tea", qty: 1 }], placed: new Date("2026-10-31T00:00:00Z") };
const shallow = { ...order };
shallow.items[0].qty = 5;
console.log(order.items[0].qty, shallow.items === order.items);
const deep = structuredClone(order);
deep.items[0].qty = 9;
console.log(order.items[0].qty, deep.placed instanceof Date);
console.log(typeof JSON.parse(JSON.stringify(order)).placed);
try { structuredClone({ save() {} }); } catch (e) { console.log(e.name); }

Output (verified)

5 true
5 true
string
DataCloneError
A shallow copy shares nested objectsStep 1 of 3

order

  • id: 1
  • items → [array A]

copy

    empty

    array A

    • { sku: 'tea', qty: 1 }

    order is an object. Its items property points to an array stored elsewhere.

    Read the steps as text
    1. order is an object. Its items property points to an array stored elsewhere.
    2. { ...order } copies the top level: a new object with the same values — including the same pointer to array A.
    3. copy.items[0].qty = 5 follows the shared pointer. Both objects now see qty 5.

    Predict#

    Predict first

    const a = { tags: ['x'] }; const b = { ...a }; b.tags = ['y']; What is a.tags?

    Interview angle#

    Say it like this — about 30 seconds

    “Objects are held by reference. Spread and Object.assign are shallow: the new object’s nested objects are the same ones as before, so changing them changes the original. structuredClone makes a deep copy and supports dates, maps, sets, typed arrays and cycles, but not functions, DOM nodes or prototypes. JSON round-trips lose dates, undefined, functions, maps and sets. In UI state I usually avoid deep copies and copy only the path I change.”

    Stays on your device. Nothing is uploaded.
    Follow-up What does structuredClone not support?
    Functions, DOM nodes, symbols as values, getters (they are evaluated), and prototypes — class instances become plain objects. Errors and many web types are supported.
    Follow-up How do you compare two objects for equality?
    === only checks identity. For content, write or use a deep-equal function that compares keys and values recursively (JS.15.07).
    Follow-up Why is copying only the changed path better in React or Redux?
    Untouched parts keep their identity, so components that depend on them can skip re-rendering; it is also much cheaper than a full deep copy.

    Practice#

    faded

    moveUser changes the original user, because spread is shallow. Copy only the path you change, and share the rest.

    Done when

    • The original user and its address are unchanged.
    • The result has the new city, and a new address object.
    • Untouched nested data, like tags, is the same object as before (shared, not copied).
    Your solution
    Ctrl/⌘ + Enter

    Remember#

    Try to answer each card before you open it. Then add them to your reviews.

    What does a shallow copy share with the original?

    All nested objects and arrays.

    Name three things structuredClone can copy that JSON cannot.

    Date, Map, Set (also cycles and typed arrays).

    What can structuredClone not copy?

    Functions, DOM nodes and prototypes (class instances become plain objects).

    What does this print?
    const a = { n: { v: 1 } };
    const b = { ...a };
    b.n.v = 2;
    console.log(a.n.v);
    2

    Go deeper

    Four layers. Stop at the one your interview needs; each ends with a quick check.

    The core ideaEvery round

    Copies made with spread are new at the top level only. Change nested data through a copy and the original changes too. Copy the path you change, or deep-copy with structuredClone.

    Check yourself: After const b = [...a], does b.push(1) change a?

    No — b is a new array. Only changes to shared nested objects leak.

    How it works underneathSenior rounds

    The structured clone algorithm is defined in the HTML Standard; the same algorithm moves data through postMessage and IndexedDB Source: HTML Standard: Structured cloning. Unsupported values throw a DataCloneError Source: MDN: The structured clone algorithm.

    Check yourself: Which standard defines structuredClone?

    The HTML Standard (the structured clone algorithm).

    Edge cases and trapsWhere people slip

    JSON drops keys whose value is undefined or a function, turns NaN and Infinity into null, and turns Map and Set into {}. structuredClone keeps object identity inside the value: if two keys point to one object, the clone’s keys point to one new object.

    Check yourself: What does JSON.stringify do with undefined values in an object?

    It leaves those keys out.

    In productionStaff-level answers

    State libraries rely on copying only changed paths: Redux reducers, React setState with spread, or Immer, which lets you “mutate” a draft and creates the minimal copy. Freeze objects in development to catch accidental mutation (JS.06.04).

    Check yourself: What does Immer do for you?

    Lets you write mutating code on a draft and produces an immutable copy of only the changed paths.

    Finished the five steps? Mark it, and its cards join your reviews.

    Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

    Interview questions this answers

    • What is the difference between a shallow and a deep copy? How do you deep copy?
    • What does structuredClone not support?