Question
Deep Cloning Objects in JavaScript: Methods, Trade-offs, and Best Practices
Question
How can a JavaScript object be deep cloned efficiently and reliably?
I have seen code such as:
const copy = eval(uneval(original));
However, that approach is non-standard and was only supported in Firefox.
I have also used:
const copy = JSON.parse(JSON.stringify(original));
but I am unsure about its efficiency and limitations.
I have come across recursive copy functions as well, but many of them seem to have edge-case problems.
What is the most practical and efficient way to deep clone an object in JavaScript, and what trade-offs should be considered?
Short Answer
By the end of this page, you will understand what deep cloning means in JavaScript, why it is different from simple assignment or shallow copying, and which cloning techniques are appropriate in modern code. You will also learn the strengths and limitations of structuredClone(), JSON.parse(JSON.stringify(...)), and manual recursive cloning.
Concept
Deep cloning means creating a completely independent copy of a value, including all nested objects and arrays.
In JavaScript, objects are assigned and passed by reference. That means this code does not create a new independent object:
const original = { user: { name: "Ava" } };
const copy = original;
copy.user.name = "Leo";
console.log(original.user.name); // "Leo"
Both variables point to the same object in memory.
A shallow copy creates a new top-level object, but nested values are still shared:
const original = { user: { name: "Ava" } };
const copy = { ...original };
copy.user.name = "Leo";
console.log(original.user.name); // "Leo"
A deep clone copies nested structures too:
const original = { : { : } };
copy = (original);
copy.. = ;
.(original..);
Mental Model
Think of an object as a folder that contains files and subfolders.
- Assignment is like writing down a second shortcut to the same folder.
- Shallow copy is like making a new top-level folder but keeping shortcuts to the same subfolders inside.
- Deep clone is like copying the entire folder tree so every subfolder and file is duplicated.
If you change a file in a true deep clone, the original folder stays unchanged.
That is why deep cloning is useful when you need a safe, isolated copy of nested data.
Syntax and Examples
Core syntax
Modern built-in approach: structuredClone()
const clone = structuredClone(original);
This is the preferred modern solution for many data structures.
JSON-based approach
const clone = JSON.parse(JSON.stringify(original));
This works only for JSON-safe data.
Example: nested object
const original = {
name: "Laptop",
specs: {
ram: 16,
storage: 512
}
};
const clone = structuredClone(original);
clone.specs.ram = 32;
console.log(original.specs.ram); // 16
console.log(clone..);
Step by Step Execution
Traceable example
const original = {
profile: {
name: "Mia",
skills: ["JavaScript", "CSS"]
}
};
const clone = structuredClone(original);
clone.profile.name = "Noah";
clone.profile.skills.push("HTML");
console.log(original);
console.log(clone);
Step by step
1. Create original
const original = {
profile: {
name: "Mia",
skills: ["JavaScript", "CSS"]
}
};
Memory idea:
originalpoints to one object.- Inside it,
profilepoints to another object. skillspoints to an array.
Real World Use Cases
Common practical uses
State updates in applications
When working with nested state, you may need a safe copy before modifying data.
const draftState = structuredClone(appState);
draftState.user.settings.theme = "dark";
Copying API data before transformation
You may want to preserve the original server response.
const rawResponse = await fetchData();
const workingCopy = structuredClone(rawResponse);
Undo/redo features
Editors and drawing tools often store snapshots.
history.push(structuredClone(currentDocument));
Test isolation
In tests, cloning fixture data prevents one test from affecting another.
const input = structuredClone(sampleUserData);
Worker communication
The structured clone algorithm is also used when passing data between threads such as Web Workers.
Real Codebase Usage
In real projects, developers often avoid deep cloning unless they actually need it, because cloning large objects has a cost.
Common patterns
1. Clone only the part you need
Instead of cloning a whole object tree, copy only the branch being changed.
const updatedUser = {
...user,
settings: {
...user.settings,
theme: "dark"
}
};
This is often more efficient than deep cloning everything.
2. Use deep cloning at system boundaries
Deep cloning is common when:
- reading external input
- creating immutable snapshots
- sanitizing data before mutation
- preparing messages for workers
3. Guard against unsupported data
If a value may contain functions or DOM elements, developers often validate before cloning.
function safeClone(value) {
try {
return structuredClone(value);
} catch {
return null;
}
}
4. Prefer data modeling over constant cloning
In larger codebases, repeated deep cloning may signal a design issue. Teams often restructure data flow so fewer full copies are needed.
5. Use libraries carefully
Common Mistakes
1. Confusing assignment with copying
const a = { x: 1 };
const b = a;
b.x = 99;
console.log(a.x); // 99
Why it happens
b is just another reference to the same object.
How to avoid it
Use a copy strategy when you need independence.
2. Assuming spread syntax is a deep clone
const a = { nested: { x: 1 } };
const b = { ...a };
b.nested.x = 99;
console.log(a.nested.x); // 99
Why it happens
Spread copies only the top level.
3. Using JSON cloning for unsupported values
const a = {
: (),
: ,
:
};
b = .(.(a));
.(b);
Comparisons
Deep clone method comparison
| Method | Deep clone? | Handles nested objects | Handles circular references | Preserves Date/Map/Set better | Handles functions | Notes |
|---|---|---|---|---|---|---|
= assignment | No | No | Yes, but shared | No | Yes, same reference | Just copies the reference |
Spread / Object.assign() | Shallow only | Top level only | N/A | No | Yes, same reference | Good for shallow updates |
JSON.parse(JSON.stringify()) | Yes, for JSON data |
Cheat Sheet
Quick reference
Assignment
const copy = original;
- Not a copy
- Same reference
Shallow copy
const copy = { ...original };
const copy2 = Object.assign({}, original);
- Copies only the top level
- Nested objects are still shared
Deep clone with modern JavaScript
const copy = structuredClone(original);
- Best built-in option for many cases
- Handles nested objects, arrays,
Date,Map,Set, and circular references - Does not clone functions or some special objects
Deep clone with JSON
const copy = JSON.parse(JSON.stringify(original));
FAQ
What is the difference between deep clone and shallow copy in JavaScript?
A shallow copy duplicates only the first level. Nested objects and arrays are still shared. A deep clone creates independent copies of nested values too.
Is structuredClone() the best way to deep clone in JavaScript?
For modern JavaScript and cloneable data, yes. It is the best built-in general-purpose option in most cases.
Why is JSON.parse(JSON.stringify(obj)) not always safe?
Because it only works for JSON-compatible data. It removes undefined and functions, converts Date objects to strings, and fails on circular references.
Can structuredClone() clone functions?
No. Functions are not supported by the structured clone algorithm.
Does spread syntax create a deep clone?
No. Spread syntax creates only a shallow copy.
Is deep cloning always a good idea?
No. It can be slower and use more memory for large objects. Often it is better to copy only the parts you need to change.
Can circular references be deep cloned?
Yes, with structuredClone(). No, with JSON cloning.
Should I use eval(uneval(obj)) for cloning?
No. It is non-standard, unsafe in many contexts, and not recommended for modern JavaScript.
Mini Project
Description
Build a small utility that creates a working copy of application settings before making changes. This demonstrates why deep cloning matters when objects contain nested configuration values.
Goal
Create a function that safely clones a settings object, updates the clone, and proves that the original object is unchanged.
Requirements
- Create a nested settings object with at least one nested object and one array.
- Deep clone the settings object using a modern JavaScript approach.
- Modify values only in the cloned object.
- Print both the original and cloned objects to show that they are independent.
Keep learning
Related questions
Get Screen, Page, and Browser Window Size in JavaScript
Learn how to get screen size, viewport size, page size, and scroll position in JavaScript across major browsers with clear examples.
How JavaScript Closures Work: A Beginner-Friendly Guide
Learn how JavaScript closures work with simple explanations, examples, common mistakes, and practical use cases for real code.
How to Change an Element's Class with JavaScript
Learn how to change, add, remove, and toggle an HTML element's class with JavaScript using events like click.