When working with objects and arrays in JavaScript, developers often encounter the concepts of shallow copy and deep copy. Understanding the difference between the two is crucial because copying objects incorrectly can lead to unexpected mutations and hard-to-track bugs.
In this blog, we’ll explore:
What shallow and deep copies are
Different ways to perform them in JavaScript
Pros and cons of each approach
Best practices for real-world applications
🔹 What is a Shallow Copy?
A shallow copy creates a new object/array but only duplicates the first level of properties.
👉 Nested objects or arrays inside remain referenced, not cloned.
Example:
let obj1 = {
name: "Anshul",
skills: ["Angular", "Node.js"]
};
let shallowCopy = { ...obj1 }; // spread operator
shallowCopy.name = "Rohit";
shallowCopy.skills.push("AWS");
console.log(obj1);
// { name: 'Anshul', skills: [ 'Angular', 'Node.js', 'AWS' ] }
console.log(shallowCopy);
// { name: 'Rohit', skills: [ 'Angular', 'Node.js', 'AWS' ] }
✅ The name property is copied independently.
❌ But the skills array is shared between both objects, so changes reflect in both.
🔹 What is a Deep Copy?
A deep copy creates a true clone of the object, including all nested objects/arrays.
👉 Modifying the copied object does not affect the original.
Example:
let obj1 = {
name: "Anshul",
skills: ["Angular", "Node.js"]
};
let deepCopy = JSON.parse(JSON.stringify(obj1));
deepCopy.skills.push("AWS");
console.log(obj1);
// { name: 'Anshul', skills: [ 'Angular', 'Node.js' ] }
console.log(deepCopy);
// { name: 'Anshul', skills: [ 'Angular', 'Node.js', 'AWS' ] }
✅ Now both objects are independent.
🔹 Ways to Perform a Deep Copy in JavaScript
1️⃣ Using JSON.parse(JSON.stringify())
✅ Quick and simple
❌ Fails with Date, undefined, Map, Set, functions, or circular references
let deepCopy = JSON.parse(JSON.stringify(obj));
2️⃣ Using structuredClone() (Modern & Recommended)
✅ Built-in, supports Date, Map, Set, TypedArrays
❌ Not supported in Internet Explorer
`let obj1 = { name: "Anshul", date: new Date(), skills: ["Angular"] };
let deepCopy = structuredClone(obj1);
deepCopy.skills.push("AWS");
console.log(obj1.skills); // [ 'Angular' ]
console.log(deepCopy.skills); // [ 'Angular', 'AWS' ]`
3️⃣ Using Lodash’s cloneDeep()
✅ Production-ready, handles complex objects
❌ Requires installing Lodash
import _ from "lodash";
let obj1 = { name: "Anshul", skills: ["Angular"] };
let deepCopy = _.cloneDeep(obj1);
deepCopy.skills.push("AWS");
console.log(obj1.skills); // [ 'Angular' ]
4️⃣ Manual Recursive Deep Copy
✅ Full control
❌ Complex for large or circular objects
function deepClone(obj) {
if (obj === null || typeof obj !== "object") return obj;
if (Array.isArray(obj)) return obj.map(item => deepClone(item));
let copy = {};
for (let key in obj) {
copy[key] = deepClone(obj[key]);
}
return copy;
}
let obj1 = { name: "Anshul", skills: ["Angular", { backend: "Node.js" }] };
let deepCopy = deepClone(obj1);
deepCopy.skills[1].backend = "Python";
console.log(obj1.skills[1].backend); // Node.js
🔹 Common Shallow Copy Methods
🔹 Summary
✅ Best Practice for Developers
Use structuredClone() for modern applications (browser & Node.js).
Use _.cloneDeep() if supporting older environments or handling complex data structures.
Avoid JSON.parse(JSON.stringify()) unless the object is simple.
Always prefer shallow copy (... or Object.assign) when nested references don’t matter.
👉 Mastering shallow vs deep copy ensures you avoid unintended mutations, keeping your code cleaner and bug-free.
Top comments (0)