paulserban.eu

Writing Edition

Paul Serban

Writing, snippets & book notes

Shallow Copy vs Deep Copy: Understanding the Differences and Use Cases

Understanding Object Copying: Shallow vs Deep Copy

Introduction: Object Copying in Programming

In modern web development, particularly in JavaScript and TypeScript, copying objects is a common operation. Whether you're working with complex data structures or passing objects between functions, understanding the difference between shallow copy and deep copy is critical. These two methods of copying objects have distinct behaviors that can significantly impact your application's performance, memory usage, and data integrity.

Object copying, in its simplest form, involves creating a new object that is a copy of an existing one. However, the depth of this copy determines whether changes to the original object affect the new one, and vice versa. In this post, we will explore the differences between shallow copy and deep copy, their respective use cases, and how you can implement them effectively in JavaScript.

Shallow Copy: The Basics

A shallow copy creates a new object, but it only copies the reference of nested objects, not the actual objects themselves. This means that if the copied object contains references to other objects, those references will point to the same objects in both the original and copied versions. As a result, changes to nested objects in one will reflect in the other.

Examples:

const originalObject = {
  a: 1,
  b: 2,
  c: { d: 3 },
};

const shallowCopy = { ...originalObject };

shallowCopy.c.d = 4;

console.log(originalObject.c.d); // 4
console.log(shallowCopy.c.d); // 4
const original = { name: "John", address: { city: "New York" } };
const shallowCopy = { ...original };

shallowCopy.name = "Jane"; // Changing a primitive field
shallowCopy.address.city = "San Francisco"; // Changing a nested object

console.log(original.name); // Output: John (No change)
console.log(original.address.city); // Output: San Francisco (Changed)

In the above example, while the change to the name field in the shallowCopy object does not affect the original, the change to the nested address.city field does. This happens because the shallow copy only copies the reference to the address object, not its value.

Use Cases for Shallow Copy:

Deep Copy: The Complete Picture

A deep copy, on the other hand, duplicates not only the original object but also the objects nested within it. This ensures that the copied object and the original object are completely independent. Changes made to one will not affect the other, even in deeply nested structures.

Example:

const original = { name: "John", address: { city: "New York" } };

const deepCopy = JSON.parse(JSON.stringify(original));

deepCopy.name = "Jane";
deepCopy.address.city = "San Francisco";

console.log(original.name); // Output: John (No change)
console.log(original.address.city); // Output: New York (No change)
const originalObject = {
  a: 1,
  b: 2,
  c: { d: 3 },
};

const deepCopy = JSON.parse(JSON.stringify(originalObject));

deepCopy.c.d = 4;

console.log(originalObject.c.d); // 3
console.log(deepCopy.c.d); // 4

In this example, changes made to the deepCopy object have no effect on the original object. This is because the deep copy creates a new instance of every object, including nested ones, thus maintaining complete independence.

Use Cases for Deep Copy:

When to Use Shallow Copy vs Deep Copy

Choosing between shallow and deep copy depends on the nature of the data you're working with and your application's specific requirements. If you're working with simple objects that do not have nested structures, a shallow copy is often more efficient and sufficient. It's also the preferred approach when performance is a concern, as deep copying large, complex objects can be resource-intensive.

However, if your objects contain nested references (arrays, objects within objects), and you want to prevent changes in one from affecting the other, deep copy is the safer option. In frameworks like React, where immutability is often required to manage state effectively, deep copying ensures that components re-render only when actual changes occur in state or props.

Shallow Copy Use Cases:

Deep Copy Use Cases:

Pros and Cons

Shallow Copy

Pros:

Deep Copy

Pros:

Deep Copy vs Shallow Copy in TypeScript

Linear or Non-linear Data Structures?

Deep and shallow copies are operations that can be applied to both linear (arrays, linked lists) and non-linear data structures (objects, trees, graphs). The categorization of the data structure is independent of the copy method used. The key distinction lies in how the data is copied, not the structure itself.

Implementation Techniques for Shallow and Deep Copy

In JavaScript, there are several ways to implement shallow and deep copy depending on your specific needs.

Shallow Copy Techniques:

Spread Operator (...)

Object.assign()

Deep Copy Techniques:

JSON.parse(JSON.stringify())

structuredClone()

Custom Recursive Functions

3. Best Practices

4. Pitfalls

Summary

MethodCopy TypeSupports Nested ObjectsSerializes Special Types (Date, Map, etc.)Performance
Object.assign()ShallowNoNoFast
Spread Operator (...)ShallowNoNoFast
JSON.parse(JSON.stringify())DeepYesNoSlow
structuredClone()DeepYesYesModerate

Conclusion: Choosing the Right Approach

Understanding the differences between shallow and deep copying is fundamental for efficient memory management and ensuring data integrity in your applications. While shallow copies are faster and sufficient for simple, non-nested objects, deep copies provide independence and protection against unintended changes when dealing with complex, nested structures.

In web development, particularly in frameworks like React and libraries like Redux, where immutability and efficient state management are essential, knowing when and how to use shallow vs deep copies can save you from hard-to-diagnose bugs and performance pitfalls. Always consider the specific needs of your project and the data structures you're working with before choosing the appropriate copy method.