In JavaScript, objects and arrays don't play by the same rules as simple numbers or strings. If you don't understand how they are copied, youβll end up with "Ghost Mutations"βwhere changing a value in one part of your app mysteriously breaks a value in another.
Letβs break down the difference using real-world architecture rather than food metaphors.
1. The Core Concept: Reference vs. Value
When you copy a Primitive (string, number), JS gives you a real copy.
When you copy an Object or Array, JS gives you a Reference (a pointer to a memory address).
2. The Shallow Copy: "The Shared Folder"
Think of a Shallow Copy like sharing a Google Drive Folder. You create a new "shortcut" to the folder, but the files inside are the exact same ones everyone else is looking at.
Real-Time Example: A User Dashboard
Imagine you have a user object with nested settings. You want to create a "Draft" of the user's settings to see how changes look before saving.
const user = {
id: 101,
profile: {
username: "dev_pro",
theme: "dark"
}
};
// Creating a Shallow Copy using the Spread Operator (...)
const userDraft = { ...user };
// Changing a top-level property (Safe)
userDraft.id = 102;
// Changing a nested property (DANGER!)
userDraft.profile.theme = "light";
console.log(user.profile.theme); // "light" π± (The original changed!)
Why it happened: The spread operator only copies the first level. The profile property in both objects still points to the same memory address. You didn't copy the profile; you shared it.
3. The Deep Copy: "The Independent Blueprint"
A Deep Copy is like taking a physical blueprint, putting it in a photocopier, and walking into a different room. Whatever you draw on your copy has zero effect on the original.
Real-Time Example: E-commerce Order History
You have a "Template Order" and you want to create a new "Customer Order" based on it. You need them to be completely separate so the customer doesn't accidentally change the template.
The Modern Solution: structuredClone()
const templateOrder = {
items: ["Laptop", "Mouse"],
specs: { warranty: "2 years" }
};
// Creating a True Deep Copy
const customerOrder = structuredClone(templateOrder);
customerOrder.specs.warranty = "1 year";
console.log(templateOrder.specs.warranty); // "2 years" β
(Original is safe!)
4. Which Tool to Use? (Comparison Table)
| Method | Type | Best For... | Drawbacks |
|---|---|---|---|
{...obj} |
Shallow | Single-level objects/React state updates. | Nested objects stay linked. |
[...arr] |
Shallow | Simple lists of strings or numbers. | Nested arrays stay linked. |
structuredClone() |
Deep | Complex Data / API Responses. | Won't copy functions/methods. |
JSON.parse/stringify |
Deep | Quick fixes in legacy code. | Corrupts Date and undefined. |
5. Real-World Engineering Scenarios
Scenario A: React State Immutability
In React, you should never mutate state. If you have a nested state object and you only do a shallow copy, React might not detect the change in the nested object, and your UI won't re-render.
Solution: Use deep copies or specific libraries like Immer to ensure fresh references.
Scenario B: Undo/Redo Functionality
If you are building an editor (like a text editor or a photo app), you need "Snapshots" of the data at different times. If those snapshots are shallow copies, every "Undo" step will be corrupted by the current changes.
Solution: A Deep Copy is required to preserve the state of the data at that specific point in time.
Summary for Developers
-
Use Shallow Copy (
...) when your object is "flat" (no objects inside objects) and you want performance. -
Use Deep Copy (
structuredClone) when you are dealing with complex data structures, API results, or configurations where you cannot risk "leaking" changes back to the source.
Top comments (0)