Shallow Copy vs Deep Copy in JavaScript – A Beginner-Friendly Guide

Table of contents
- 🟡 What is a Shallow Copy?
- 🔵 What is a Deep Copy?
- 🧾 Analogy: Copying a Notebook
- 🔧 All the Ways to Shallow Copy in JavaScript
- 🔧 All the Ways to Deep Copy in JavaScript
- 🔄 React: Shallow Copy vs Deep Copy in State Management
- ❓ Frequently Asked Questions (FAQ)
- 1. Why does my original object change when I modify the copy?
- 2. How can I check if a copy is shallow or deep?
- 3. What is a circular reference?
- 4. Is structuredClone() safe for deep copying?
- 5. Can I write my own deep copy function?
- 6. Is spread operator a deep copy?
- 7. Does React do deep copying of state?
- 8. Should I always use deep copy?
- 9. What’s the difference between deep copy and deep freeze?
- ✅ Final Thoughts

When working with objects and arrays in JavaScript, understanding how copying works is essential to avoid bugs and unexpected behavior. This article breaks down shallow copy vs deep copy in the simplest way possible, with examples, analogies, React use cases, and answers to frequently asked questions.
🟡 What is a Shallow Copy?
A shallow copy means copying only the top-level properties of an object or array. If the object has nested values (like another object or array), the copy still points to the original nested values.
📦 Example:
const original = {
name: "Yash",
address: { city: "Delhi" }
};
const copy = { ...original }; // Shallow copy using spread operator
copy.address.city = "Mumbai"; // Modifying nested property in the copy
console.log(original.address.city); // 👉 'Mumbai' (original affected)
Here, copy
and original
both share the same address
object reference. So, changing the city in copy.address
also affects original.address
.
🔵 What is a Deep Copy?
A deep copy creates a brand-new object and recursively copies all nested values, so the new object is fully independent of the original.
📦 Example:
const original = {
name: "Yash",
address: { city: "Delhi" }
};
const deep = JSON.parse(JSON.stringify(original)); // Deep copy via JSON method
deep.address.city = "Mumbai"; // Modifying nested property in deep copy
console.log(original.address.city); // 👉 'Delhi' (original untouched)
This approach ensures that changes to the copied object do not affect the original, but note that it has limitations (discussed later in this blog).
🧾 Analogy: Copying a Notebook
Imagine you have a notebook with pages and photos:
Shallow Copy = You photocopy a notebook with notes and diagrams in it, but you only photocopy the pages with notes and put stickers saying “see original diagrams from the book” where the diagrams were.
Deep Copy = You rewrite every page and recopy the diagrams as well. Now it’s a full, standalone copy.
Changing anything in the shallow copy’s diagrams affects the original notebook (since they are reference to the original one). In deep copy, both notebooks are completely independent.
🔧 All the Ways to Shallow Copy in JavaScript
Objects:
const copy = { ...original }; // Using spread operator
const copy = Object.assign({}, original); // Using Object.assign
Both methods create a new object and copy top-level properties. ( nested properties still refer the original memory address ).
Arrays:
const arrCopy = [...array]; // spread operator
const arrCopy = array.slice(); // slice method
const arrCopy = Array.from(array); // Array.from method
These methods create new arrays, but do not deeply clone nested elements.
🔧 All the Ways to Deep Copy in JavaScript
1. JSON.parse(JSON.stringify())
const deepCopy = JSON.parse(JSON.stringify(obj));
✅ Easy to use and works for plain objects.
❌ Fails when the object contains:
undefined
function
sDate
,Map
,Set
Circular references
2. structuredClone()
(modern method)
const deepCopy = structuredClone(obj);
✅ Handles complex types like Date
, Map
, Set
, and supports circular references.
❌ Not supported in Internet Explorer and some older environments.
3. Lodash's cloneDeep()
import cloneDeep from 'lodash/cloneDeep';
const deepCopy = cloneDeep(obj);
✅ Safe, widely used, and handles nearly every edge case including deeply nested structures and circular references.
🔄 React: Shallow Copy vs Deep Copy in State Management
Initial State:
const [user, setUser] = useState({
name: "Yash",
address: { city: "Delhi" }
});
This state includes a nested address
object.
❌ Shallow Copy (Buggy)
const updateCity = () => {
const updatedUser = { ...user }; // Shallow copy of user
updatedUser.address.city = "Mumbai"; // Directly mutating nested object
setUser(updatedUser); // React may not re-render
};
Since updatedUser.address
is still a reference to user.address
, this mutation can lead to bugs and stale renders. ( also now the original address’s city is changed to Mumbai ).
✅ Deep Copy (Safe)
const updateCity = () => {
const updatedUser = {
...user,
address: { ...user.address, city: "Mumbai" } // Creating a new nested object
};
setUser(updatedUser); // React sees new reference, triggers re-render
};
This method ensures immutability at the level you need. ( since we created a new nested object, the original one won’t be mutated ).
✅ Using cloneDeep
for deeply nested structures
import cloneDeep from "lodash/cloneDeep";
const updateCity = () => {
const updatedUser = cloneDeep(user); // Full deep copy
updatedUser.address.city = "Mumbai";
setUser(updatedUser);
};
Lodash's cloneDeep
ensures that all levels are independently copied. ( best for deep copying stuff )
❓ Frequently Asked Questions (FAQ)
1. Why does my original object change when I modify the copy?
Because you made a shallow copy, and the nested values are still shared.
2. How can I check if a copy is shallow or deep?
Try modifying a nested property in the copy and see if it affects the original.
3. What is a circular reference?
A circular reference is when an object refers to itself directly or indirectly.
const obj = {};
obj.self = obj; // Circular reference
This breaks JSON.stringify()
because it causes infinite recursion.
4. Is structuredClone()
safe for deep copying?
Yes, it's a modern built-in method that handles deep cloning of most types.
5. Can I write my own deep copy function?
Yes, but it’s tricky. You need to handle all data types and circular references. It's better to use a library like Lodash.
6. Is spread operator a deep copy?
No, it only creates a shallow copy.
7. Does React do deep copying of state?
No. React doesn’t clone state for you. You are responsible for ensuring immutability.
8. Should I always use deep copy?
Not necessarily. Use shallow copy for flat data. Use deep copy when dealing with nested or complex structures that need isolation.
9. What’s the difference between deep copy and deep freeze?
A deep copy creates a new object, fully detached. A deep freeze makes an object and all its nested values immutable, preventing any changes.
✅ Final Thoughts
Understanding the difference between shallow and deep copying is crucial for writing bug-free JavaScript, especially when dealing with nested objects and arrays — like in React state. Always pick the right type of copy based on how deep your data goes.
Subscribe to my newsletter
Read articles from Yash Grover directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
