Deep Copy and Shallow Copy


When you're coding in JavaScript, it's important to understand how data is stored and copied in memory. Interviewers love asking about it - especially using objects and arrays!
Before we get into copying data, let’s understand where data is stored.
📦 Stack vs Heap
🧱 Stack:
Stores simple (primitive) values like numbers, strings, boolean
Fast and small.
Stores actual values.
🏗️ Heap:
Stores complex values like objects and arrays.
Bigger and slower.
Stack stores a reference (pointer) to the actual object in the heap.
📦Trade Off Between these two
1️⃣ Pass by Value
Used with primitive types (number, string, boolean)
const p1 = {
name: "John",
age: 20
};
const p2 = {
name: p1.name,
age: p1.age
};
p2.name = "Gaurav";
console.log(p1.name); // "John"
✅ Here, p2.name
is a copy of p1.name
, not a reference. So changes to p2
do not affect p1
.
2️⃣ Pass by Reference
Used with objects and arrays
const obj = {
name: "Gaurav",
address: {
city: "Varanasi"
}
};
const newObj = { ...obj }; // Looks like a copy => Shallow Copy
You might think newObj
is a full copy. But...
newObj.address.city = "Delhi";
console.log(obj.address.city); // ❗ "Delhi"
😱 Why did obj
also change?
🧠 Because the address
object is stored in the heap, and both obj.address
and newObj.address
point to the same place in memory!
This is called a shallow copy.
🥘 Shallow Copy
A shallow copy copies only the top-level properties. Nested objects are still shared.
jsCopyEditconst obj = {
name: "Gaurav",
address: {
city: "Varanasi"
}
};
const newObj = { ...obj }; // shallow copy
✅ obj.name
is copied by value.
❌ obj.address
is copied by reference (same memory).
That’s why if you change newObj.address.city
, it affects obj
.
©️Deep Copy
A deep copy copies everything — even nested objects — into new memory.
✅ Option 1: Manual Deep Copy
const obj2 = {
...obj,
address: { ...obj.address }
};
Now, obj2.address
is a new object, not shared with obj
.
✅ Option 2: JSON Method
const objString = JSON.stringify(obj);
const obj3 = JSON.parse(objString);
This creates a completely new object, including all nested data.
🚫 But it doesn't work well with:
Functions
undefined
Dates
Circular references
🧠 Visualizing Stack and Heap
🧠 Summary Table
Concept | Applies To | Memory Used | Shared? | |
Pass by Value | Primitives | Stack | ❌ No | |
Pass by Reference | Objects/Arrays | Stack + Heap | ✅ Yes | |
Shallow Copy | Objects/Arrays | Stack + Heap | ✅ Part | |
Deep Copy | Objects/Arrays | Stack + Heap | ❌ No |
"In JavaScript, primitive values are passed by value and stored in stack, but objects and arrays are passed by reference. Spread operator gives a shallow copy — only one level deep. For true deep copies, we can use JSON methods or libraries like Lodash."
📌 Final Thoughts
Use spread operator when you only need a shallow copy.
Use manual or JSON deep copy when you want to fully separate the copy from the original.
Always understand what's in the heap - that’s where shared bugs come from.
Subscribe to my newsletter
Read articles from Gaurav Kumar Maurya directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
