Shallow Copy vs Deep Copy in JavaScript and Python
The issue of preventing future mutation of the copied original exists both in JavaScript and Python. In Python, both lists and dictionaries are mutable reference types, similar to arrays and objects in JavaScript. When you copy these structures, you must be aware of whether you are making a shallow or deep copy.
- Shallow Copy: Creates a new object, but inserts references into it to the objects found in the original. This means that changes to mutable objects within the copied structure will affect the original.
- Deep Copy: Creates a new object and recursively adds copies of nested objects found in the original, ensuring that changes to the copied structure do not affect the original.
Deep Copy vs Shallow Copy in JavaScript
You can create a shallow copy of an array or object using the spread operator or Object.assign.
const originalArray = [1, 2, [3, 4]]; // Shallow copy using spread operator const shallowCopyArray = [...originalArray]; // Modifying the nested array in the shallow copy shallowCopyArray[2][0] = 'changed'; console.log("Original Array:", originalArray); // Original Array: [1, 2, ['changed', 4]] console.log("Shallow Copy Array:", shallowCopyArray); // Shallow Copy Array: [1, 2, ['changed', 4]]
You can use deep copy Using JSON.parse and JSON.stringify, but it requires workarounds with dates and undefined, and you can’t copy functions. This article describes better methods.
const originalArray = [1, 2, [3, 4]]; // Deep copy using JSON methods const deepCopyArray = JSON.parse(JSON.stringify(originalArray)); // Modifying the nested array in the deep copy deepCopyArray[2][0] = 'changed'; console.log("Original Array:", originalArray); // Original Array: [1, 2, [3, 4]] console.log("Deep Copy Array:", deepCopyArray); // Deep Copy Array: [1, 2, ['changed', 4]]
const originalObject = { a: 1, b: { c: 2 } }; // Deep copy using JSON methods const deepCopyObject = JSON.parse(JSON.stringify(originalObject)); // Modifying the nested object in the deep copy deepCopyObject.b.c = 'changed'; console.log("Original Object:", originalObject); // Original Object: { a: 1, b: { c: 2 } } console.log("Deep Copy Object:", deepCopyObject); // Deep Copy Object: { a: 1, b: { c: 'changed' } }
In JavaScript, you can’t edit primitives. In a variable, you don’t store the value, you store the address of that value in memory. E.g. When you assign new value to a string variable, you throw away the old value and assign the new value.
Objects (also arrays which are objects) are reference values, they can be mutated. E.g. when you use the push() method, js reaches into memory and adds this new item to that existing array. The address doesn’t change.
const hobbies = ['Sports', 'Cooking']; hobbies.push('Working'); console.log(hobbies); // ['Sports', 'Cooking', 'Working']
This is why, even though hobbies are defined with const
, we can change their elements. Because const
doesn’t mean the value can’t be edited but it means the variable can’t be overwritten.
If I tried to reassign hobbies, I’d get an error:
hobbies = []; // results in error
Deep Copy vs Shallow Copy in Python
Here’s an example in Python:
import copy # Original list original_list = [1, 2, [3, 4]] # Shallow copy shallow_copy = original_list[:] # Deep copy deep_copy = copy.deepcopy(original_list) # Modifying the nested list in the shallow copy shallow_copy[2][0] = 'changed' print("Original List:", original_list) # Original List: [1, 2, ['changed', 4]] print("Shallow Copy:", shallow_copy) # Shallow Copy: [1, 2, ['changed', 4]] print("Deep Copy:", deep_copy) # Deep Copy: [1, 2, [3, 4]]
In this example, modifying the nested list in the shallow copy also affects the original list, but the deep copy remains unchanged.
More detailed articles with more methods:
https://javascript.plainenglish.io/how-to-get-a-perfect-deep-copy-in-javascript-bbf6c670fb47
https://betterprogramming.pub/shallow-copy-vs-deep-copy-in-python-357e5f502bf9