Lesson 38 of 80
Copying a nested object by reference bites everyone eventually. structuredClone() is the built-in fix — and it's not the same thing as the JSON.parse(JSON.stringify()) trick people reach for instead.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Assigning an object doesn't copy it — const b = a makes b point at the same object a does, so mutating one mutates both. A shallow copy ({...a}, Object.assign) fixes the top level but still shares any nested objects. A deep copy recursively copies every nested level so the two are fully independent.
structuredClone() is a global function, built into the language and browsers since 2022, that does a real deep copy using the same algorithm the platform uses internally to pass data between workers, tabs, and postMessage. It's not a library trick — it's how the engine itself already knows how to duplicate values.
const original = {
user: { name: "Dee", joined: new Date("2023-01-01") },
tags: new Set(["admin", "beta"]),
scores: [1, 2, 3],
};
const copy = structuredClone(original);
copy.user.name = "Sam";
original.user.name;
// "Dee" -- untouched, because copy.user is a fully separate object
copy.tags.has("admin");
// true -- Sets clone correctly
copy.user.joined instanceof Date;
// true -- Dates clone as real Date objects, not strings
Compare the old workaround:
const jsonCopy = JSON.parse(JSON.stringify(original));
jsonCopy.user.joined;
// "2023-01-01T00:00:00.000Z" -- a STRING now, not a Date
jsonCopy.tags;
// {} -- Set silently became an empty object, all its values gone
JSON.stringify only knows plain objects, arrays, strings, numbers, booleans, and null. Everything else — Date, Map, Set, undefined — either gets mangled into something else or dropped entirely, with no warning.
DataCloneError if any value in the tree is a function, a class instance with a non-cloneable prototype, or a live DOM element. If your data has methods attached, this isn't the right tool — you'd typically strip functions out first or restructure the data.undefined values, function properties, and Symbol keys just vanish from the JSON output entirely — no error, no warning, just gone. That's fine when you genuinely want a "clean data" snapshot, but it's a trap when you didn't realize you had one of those types in there.This is the same reference-vs-copy question that drives immutability and pure functions — the whole reason a "copy" needs defining precisely is that JS objects are held by reference. structuredClone is the platform finally giving you a correct, built-in answer instead of everyone hand-rolling their own deep-copy function or reaching for the leaky JSON trick.