Shallow Copy vs Deep Copy in JavaScript: A Common Confusion I Faced While Interviewing a Candidate!

Shallow Copy vs Deep Copy in JavaScript: A Common Confusion I Faced While Interviewing a Candidate!

Photo by KOBU Agency on Unsplash

During a recent interview with a candidate, we got into an interesting discussion about shallow copy and deep copy in JavaScript. Initially, I thought I had a solid understanding of the concept, but the candidate’s response made me stop and think for a moment. 🤔

They said, “Shallow copy does copy the reference!” which made me wonder if I might be missing something.

After reflecting on it, I want to clarify this common confusion and share my understanding of how shallow and deep copies actually work.

Shallow Copy in JavaScript

A shallow copy creates a new object with the top-level properties duplicated (i.e., primitive values like strings, numbers, booleans, etc.). However, when it comes to nested objects or arrays, the shallow copy copies the reference to those nested values instead of duplicating the entire object.

So, any changes made to the nested objects/arrays in the shallow copy will affect the original object.

Shallow Copy Example

Here’s an example to demonstrate how shallow copy works:

const obj1 = { name: "Roja", birthDate: new Date(), details: { city: "Chennai" } };
const obj2 = { ...obj1 }; // Shallow copy

obj2.name = "John";  // Independent change
obj2.details.city = "Bangalore";  //  Mutates obj1
obj2.birthDate.setFullYear(2025);  // Mutates obj1's birthDate as well

console.log(obj1.details.city); // "Bangalore"  (mutated!)
console.log(obj1.birthDate.getFullYear()); // 2025 (mutated!)

What happened here?

  • obj2.name = "John": This worked fine! Since name is a primitive value, it was copied and changes didn't affect obj1.

  • obj2.details.city = "Bangalore": This changed both obj2 and obj1, because the details object is nested, and the shallow copy only copies the reference, not the object itself.

  • obj2.birthDate.setFullYear(2025): This also modified the original obj1 object, as birthDate is an object (of type Date), and its reference was copied in the shallow copy.

When to Use Shallow Copy?

Shallow copy works great for top-level properties where there are only primitive values. But for complex, deeply nested objects or arrays, using shallow copy can lead to unintentional mutations in the original object, as seen in the example above.

How to Make a True Deep Copy in JavaScript

If you need to fully duplicate an object, including nested objects, and avoid shared references, you'll need to use deep copy techniques.

Deep Copy Methods in JavaScript

1. structuredClone() (Modern Approach)

structuredClone() is a built-in JavaScript function that creates a true deep copy of an object. It works with modern browsers and handles more complex data types, including Date, Map, Set, and RegExp.

const obj2 = structuredClone(obj1); // Deep copy

2. JSON.parse(JSON.stringify()) (For Simple Objects)

This method serializes the object into a JSON string and then deserializes it back into a new object. It works for simple objects but does not handle special data types like Date, functions, or non-enumerable properties

const obj2 = JSON.parse(JSON.stringify(obj1)); // Deep copy

3. lodash.cloneDeep() (For Complex Objects)

lodash.cloneDeep() is a third-party utility from the popular Lodash library. It creates a deep copy of an object and handles edge cases like circular references, as well as special objects like Date and Map.

const obj2 = lodash.cloneDeep(obj1); // Deep copy

Which Method Should You Use?

  • structuredClone() is the most modern and handles complex data types, but it’s only supported in newer browsers.

  • JSON.parse(JSON.stringify()) is a simple and lightweight method but should be avoided if you're working with complex objects like Date or custom functions.

  • lodash.cloneDeep() is the most robust solution for complex objects, handling all edge cases, including circular references and special types.

Key Takeaways:

  1. Shallow Copy: Duplicates top-level properties but copies the reference for nested objects/arrays. Changes to nested objects affect the original.

  2. Deep Copy: Creates a fully independent copy of the object, including nested objects, ensuring no shared references.

  3. Use structuredClone() for modern use cases, JSON.parse(JSON.stringify()) for simple objects, and lodash.cloneDeep() for complex objects.

Conclusion

This interview discussion made me realize how important it is to fully understand the difference between shallow and deep copies, especially when working with objects in JavaScript. It’s always a great learning experience to revisit core concepts like these.

Have you faced any similar moments of confusion or learning during interviews or while coding? Feel free to share your thoughts or experiences in the comments below!

Let’s keep learning together! 💬