Table of contents
When dealing with arrays and objects in JavaScript, it is often necessary to create copies of these structures. Since both arrays and objects are mutable, understanding the implications of modifying a copied array or object on the original is crucial.
Shallow Copy
In Shallow copy, we copy one array or object into another array or object
If the array is not nested then changing the copied array will not change the original array
If an array is nested then the nested array will have the same reference as the original array.
Copying the original array using the spread operator
let originalArr = [1,2,3,4]
let copiedArr = [...originalArr]
console.log(originalArr) // [1,2,3,4]
console.log(copiedArr ) // [1,2,3,4]
Copying the original array using Object.assign
let originalArr = [1,2,3,4]
let copiedArr = Object.assign([],originalArr)
console.log(originalArr) // [1,2,3,4]
console.log(copiedArr ) // [1,2,3,4]
Copying the original array using Array.from
let originalArray = [1, 2, 3, 4]
let copiedArray = Array.from(originalArray)
console.log(originalArray) // [1,2,3,4]
console.log(copiedArray) // [1,2,3,4]
Copying the original array using the slice method
let originalArray = [1, 2, 3, 4]
let copiedArray = originalArray.slice(0)
console.log(originalArray) // [1,2,3,4]
console.log(copiedArray) // [1,2,3,4]
Nested array Scenario
let originalArray = [1, 2, 3, 4, [5, 6, 7, 8]]
let copiedArray = [...originalArray]
copiedArray[4].push(9)
console.log(originalArray); // [ 1, 2, 3, 4, [ 5, 6, 7, 8, 9 ] ]
console.log(copiedArray); // [ 1, 2, 3, 4, [ 5, 6, 7, 8, 9 ] ]
As we can see changing the copied array changes the original array as well.
In a shallow copy, the copied array maintains references to the same nested arrays as the original array. For example, if the original array includes the nested array
[5, 6, 7, 8]
, the copied array will also refer to the same nested array.So changing the nested part of the copied array will result in changing the nested part of the original array.
Nested object with Object.freeze
Object.freeze
method is used to make an object immutable.So let's try what happens if we use
Object.freeze
on original object and try to change the copied object.
let person = {
firstName: "John",
lastName: "Doe",
age: 30,
address: {
street: "123 Main Street",
city: "Anytown",
zipCode: "12345",
country: "Exampleland"
}
};
Object.freeze(person)
let copiedPerson = { ...person }
copiedPerson.address.city = "Newtown"
console.log(person);
console.log(copiedPerson);
- In the person object city will be changed to Newtown, which means Object.freeze does the shallow freeze. So the solution for this issue is Deep copy.
Deep copy
- We can use several libraries like lodash, Ramda, and others which provide the facility for Deep copy.
Deep copy using lodash
var loadash = require('lodash');
const originalObject = { a: 1, b: { c: 2 } };
// Deep copy using Lodash's cloneDeep
const lodashDeepCopy = loadash.cloneDeep(originalObject);
lodashDeepCopy.a = 10;
lodashDeepCopy.b.c = 20;
console.log(originalObject); // Output: { a: 1, b: { c: 2 } }
console.log(lodashDeepCopy); // Output: { a: 10, b: { c: 20 } }
Changing the value inside the lodashDeepCopy does not change the originalObject.
Deep copy using Vanilla js
const makeDeepCopy = (data) => {
// if passed data is not a object then return
if (typeof data !== "object" || data === null) {
return data
}
// if data is a array then create a empty array else a empty a object
let deepCloneObject = Array.isArray(data) ? [] : {}
// iterating over each element
for (let key in data) {
const value = data[key]
// running the makeDeepCopy to check whether the element is of type object or not.
deepCloneObject[key] = makeDeepCopy(value);
}
return deepCloneObject
}
let arr1 = [1, 2, 3, 4, [5, 6, 7, 8]]
let arr2 = makeDeepCopy(arr1)
arr2[4].push(9)
console.log(arr1); // [ 1, 2, 3, 4, [ 5, 6, 7, 8 ] ]
console.log(arr2); // [ 1, 2, 3, 4, [ 5, 6, 7, 8, 9 ] ]
let obj1 = {
firstName: 'John',
lastName: 'Doe',
age: 30,
address: {
street: '123 Main Street',
city: 'New york',
zipCode: '12345',
country: 'Exampleland'
}
}
let obj2 = makeDeepCopy(obj1)
obj2.address.city = "New Town"
console.log(obj1);
console.log(obj2);
Conclusion
Shallow copy is useful when the array or object to be copied is not nested.
Deep copy should be preferred when the array or object is nested.
But while working with Deep copy performance should also be considered as Deep copy operation is slower than Shallow copy.