Learning Part 3: Understanding Data Copying in JavaScript
In this part, I explore how to copy and save data in JavaScript. During the development of my browser extension, I learned about two key methods: shallow copy and deep copy. These methods provide different ways to manage and store data effectively, depending on the complexity of the data structures involved.
So when to use what but first let have a understanding what is shallow copy and what is deep copy
Shallow Copy:
- Definition: A shallow copy creates a new object or array and copies the references to the original elements or properties. If the elements or properties are primitives (like numbers, strings, or booleans), the actual value is copied. However, if they are objects or arrays, only the reference to those objects or arrays is copied, not the objects themselves.
- Simple Data Structures: If your data structure is simple and doesn’t contain nested objects or arrays (e.g., just an array of numbers or a flat object with string properties), a shallow copy is sufficient.
- Memory Efficiency: When working with large data structures where memory usage is a concern, and you don’t need to modify nested objects independently of the original, a shallow copy is more memory-efficient.
- Example Use Case: Saving a URL and text from a tab is a scenario where a shallow copy is appropriate because both are simple strings.
Memory Usage: Since shallow copies only copy references to nested objects, they are more memory-efficient when dealing with large data structures. However, any changes made to the nested objects in the copy will affect the original object
Deep Copy:
- Definition: A deep copy creates a new object or array and recursively copies all nested objects and arrays. This means that the original and the copied objects are completely independent of each other.
- Complex Data Structures: If your data structure includes nested objects or arrays and you need to modify the copy without affecting the original, a deep copy is necessary.
- Data Integrity: When you need to ensure that changes to the copied data do not affect the original data, a deep copy is required.
- Example Use Case: Cloning a complex configuration object that includes nested arrays and objects to modify without altering the original settings.
Memory Usage: Deep copies consume more memory because they duplicate every nested object and array, creating entirely new copies. This can be expensive in terms of both memory and processing time, especially for large or complex structures.
Let explain it with the example of the saved text and the url
Example Scenario: Saving URL and Text
Imagine you have the following data representing a webpage's current tab:
const currentTabData = {
url: "https://example.com",
text: "Welcome to Example.com!"
};
You want to save this data for later use. Let's explore how shallow and deep copies handle this.
Using Shallow Copy
Since url and text are both strings (primitive data types), a shallow copy will suffice.
领英推è
Shallow Copy Implementation:
// Original data
const currentTabData = {
url: "https://example.com",
text: "Welcome to Example.com!"
};
// Creating a shallow copy
const savedTabDataShallow = { ...currentTabData };
// Modifying the copy
savedTabDataShallow.text = "Updated text for the saved tab.";
console.log("Original Text:", currentTabData.text); // Output: "Welcome to Example.com!"
console.log("Shallow Copy Text:", savedTabDataShallow.text); // Output: "Updated text for the saved tab."
Explanation:
- Copying Process: The spread operator { ...currentTabData } creates a new object and copies the values of url and text.
- Modification: Changing savedTabDataShallow.text does not affect currentTabData.text because strings are immutable and are copied by value.
- Result: The original data remains unchanged, ensuring data integrity.
Using Deep Copy
While you can perform a deep copy, it's unnecessary for this simple structure.
Deep Copy Implementation:
// Original data
const currentTabData = {
url: "https://example.com",
text: "Welcome to Example.com!"
};
// Creating a deep copy using JSON methods
const savedTabDataDeep = JSON.parse(JSON.stringify(currentTabData));
// Modifying the copy
savedTabDataDeep.text = "Updated text for the saved tab.";
console.log("Original Text:", currentTabData.text); // Output: "Welcome to Example.com!"
console.log("Deep Copy Text:", savedTabDataDeep.text); // Output: "Updated text for the saved tab."
Explanation:
- Copying Process: JSON.parse(JSON.stringify(currentTabData)) creates a completely new object by serializing and deserializing the original.
- Modification: Changing savedTabDataDeep.text does not affect currentTabData.text, similar to the shallow copy in this case.
- Result: The original data remains unchanged.
Why Shallow Copy is Preferable Here
- Simplicity of Data:
- Performance and Memory Efficiency:
- Unnecessary Overhead:
- Maintainability:
When Deep Copy Might Be Unnecessary or Harmful
- Increased Memory Consumption: Even though it doesn't provide additional benefits for simple data, deep copying consumes more memory, which can be problematic in memory-constrained environments.
- Performance Impact: Deep copying large or frequently accessed objects can slow down your application, leading to a poor user experience.
- Potential Bugs: Introducing unnecessary deep copies can make the codebase more complex, increasing the risk of bugs and maintenance challenges.