Shallow Copy vs. Deep Copy (structuredClone)
Quick Overview
`{...obj}` copies only the top level, so nested objects stay shared and editing one edits both. `structuredClone()` walks the entire graph, which is why it is the one that actually detaches.
Deep Dive
1. Copies & Object References
In JavaScript, primitives copy by value, but objects and arrays copy by reference.
2. Why It Matters
Assigning an object to a new variable (const b = a) creates a shared reference pointer. Modifying a property on b silently mutates a!
3. Shallow Copy vs. Deep Copy
- Shallow Copy (
{ ...obj }orObject.assign()): Copies top-level properties. Nested objects still share references in memory! - Deep Copy (
structuredClone(obj)): Creates a completely independent clone of the entire object graph, including all nested objects and arrays.
const original = {
name: "App",
settings: { theme: "dark" },
};
// Shallow Copy Problem
const shallow = { ...original };
shallow.settings.theme = "light";
console.log(original.settings.theme); // "light" (Mutated original settings!)
// Native Deep Clone (Modern ES2022 Standard)
const deepCopy = structuredClone(original);
deepCopy.settings.theme = "blue";
console.log(original.settings.theme); // "light" (Original untouched!)
4. Visual Memory Reference Layout
[ Shallow Copy ] -> copy.settings ---+
+--> Shares same nested memory cell!
[ Original ] -> orig.settings ---+
[ Deep Clone ] -> clone.settings ----> Independent new memory cell!
5. Common Mistakes
- Using
JSON.parse(JSON.stringify(obj)): The old JSON deep copy trick loses Functions,undefined,Dateobjects,Set,Map, and crashes on circular references. Always use nativestructuredClone(). - Assuming Spread is Deep: Spread operator ONLY copies 1 level deep!
6. Try It Yourself
Write it yourself. The tests below run against your code.
Deep Clone Object to Prevent Mutation
Examples
7. Next Steps
Use structuredClone() for safe deep cloning. Next, let's explore modern native array grouping with Object.groupBy()!
Next Up in JavaScript Engine & Core Language
Data Types in JavaScript: Primitives vs. Objects
Primitives copy by value and objects copy by reference, so `b = a` duplicates a number but shares an object. That single distinction explains most surprise mutations in a codebase.
Variables: const, let & var (The Box Metaphor)
`const` prevents reassignment, not mutation: a `const` object's properties can still be changed. `let` is scoped to its block, while `var` is function-scoped and leaks out of loops.
Strings & Template Literals `${}`
Only backticks interpolate: `${user}` reads the variable, while the identical text in quotes prints literally. Strings are immutable, so every method returns a new one rather than editing in place.