Understanding Shallow vs Deep Copy in JavaScript
When working with objects and arrays in JavaScript, developers often encounter the need to create copies of these data structures. However, not all copies are created equal. In this article, we will explore the differences between shallow and deep copies, their implications, and how to properly implement each method in JavaScript. This understanding is crucial for preventing unintended side effects in your applications.
What is a Copy?
A copy is simply a duplicate of a data structure, such as an object or an array. In JavaScript, copying is essential when you want to preserve the original object while manipulating a new one. However, the way in which the copy is made can lead to different results—this is where shallow and deep copying come into play.
Shallow Copy Explained
A shallow copy of an object creates a new object that is a copy of the original object but only copies the references of nested objects, not their actual values. This means that if the original object contains other objects or arrays, the copied object will still reference these nested structures rather than creating copies of them.
How to Create a Shallow Copy
There are several ways to create a shallow copy in JavaScript:
- Object Spread Operator (
{...obj}) - Array Spread Operator (
[...arr]) - Object.assign()
Examples of Shallow Copy
Let’s look at some examples:
1. Using Object Spread Operator
const original = { a: 1, b: { c: 2 } };
const shallowCopy = {...original};
shallowCopy.a = 3;
shallowCopy.b.c = 4;
console.log(original); // Output: { a: 1, b: { c: 4 } }
console.log(shallowCopy); // Output: { a: 3, b: { c: 4 } }
2. Using Object.assign()
const original = { x: 10, y: { z: 20 } };
const shallowCopy = Object.assign({}, original);
shallowCopy.x = 30;
shallowCopy.y.z = 40;
console.log(original); // Output: { x: 10, y: { z: 40 } }
console.log(shallowCopy); // Output: { x: 30, y: { z: 40 } }
As shown in the examples above, changes to the nested object b or y in the shallow copy affect the original object as well since both point to the same reference.
Deep Copy Explained
A deep copy, on the other hand, creates a new object and recursively copies every property from the original object, including the nested objects. Thus, the result is a complete clone with no shared references.
How to Create a Deep Copy
Deep copying can be achieved using the following methods:
- JSON.parse(JSON.stringify())
- Recursive function
- Libraries such as Lodash
Examples of Deep Copy
Let’s dive into some examples of creating deep copies:
1. Using JSON methods
const original = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.a = 3;
deepCopy.b.c = 4;
console.log(original); // Output: { a: 1, b: { c: 2 } }
console.log(deepCopy); // Output: { a: 3, b: { c: 4 } }
2. Using a Recursive Function
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const copy = Array.isArray(obj) ? [] : {};
for (const key in obj) {
copy[key] = deepCopy(obj[key]);
}
return copy;
}
const original = { x: 10, y: { z: 20 } };
const deepCopy = deepCopy(original);
deepCopy.x = 30;
deepCopy.y.z = 40;
console.log(original); // Output: { x: 10, y: { z: 20 } }
console.log(deepCopy); // Output: { x: 30, y: { z: 40 } }
When to Use Shallow vs. Deep Copy
The choice between using a shallow or deep copy depends on your use case:
- Use Shallow Copy: When you are sure that your object does not contain nested objects that need to be independently modified.
- Use Deep Copy: When your object contains nested structures, and you need a completely independent duplicate.
Common Pitfalls
It’s crucial to understand the differences between shallow and deep copies because mistakenly using one when the other is required can introduce bugs and unexpected behavior. Here are some common pitfalls:
- Modifying a deep-nested structure in a shallow-copied object can inadvertently affect the original object.
- Using JSON methods for deep copying has limitations—functions,
undefined, and non-serializable objects (likeDateorMap) will be lost.
Conclusion
The decision between shallow and deep copies is a foundational concept in JavaScript programming that affects how data structures are manipulated. By understanding the nature of these copies, you can write more predictable and error-free code. Remember to consider your application’s requirements and use the appropriate copying method based on the context.
Stay informed and practice these concepts as they are pivotal to mastering JavaScript object manipulation!
