DEV Community

Cover image for Shallow copy and Deep copy
Jyoti chaudhary
Jyoti chaudhary

Posted on

Shallow copy and Deep copy

1. Shallow Copy

A shallow copy creates a new object or array but does not recursively copy the nested objects/arrays inside it. Instead, the references to the nested objects are copied, so changes to nested objects affect both the original and the copied objects.
In this process, only the top-level properties are copied, while nested objects or arrays still reference the original memory location. This means that if you change the nested properties in one object, those changes will reflect in the other because they share the same memory reference.

Example 1: Shallow Copy using Object.assign():
// Original Object
const original = {
  name: "John",
  age: 30,
  address: {
    city: "New York",
    zip: "10001"
  }
};

// Shallow copy using Object.assign()
const shallowCopy = Object.assign({}, original);

// Modify the nested object in the shallow copy
shallowCopy.address.city = "Los Angeles";

console.log(original.address.city); // Output: "Los Angeles"
console.log(shallowCopy.address.city); // Output: "Los Angeles"
console.log(original); // Output: {name: 'John', age: 30, address: {city: 'Los Angeles', zip: '10001'}}
console.log(shallowCopy); // Output: {name: 'John', age: 30, address: {city: 'Los Angeles', zip: '10001'}}

Enter fullscreen mode Exit fullscreen mode
Explanation: In the above example:
  • original is an object with a nested object address.
  • shallowCopy is created using Object.assign(), which copies only the first level of properties from original to shallowCopy.
  • However, since address is a reference to the same object in both original and shallowCopy, modifying shallowCopy.address affects both objects.
Example 2: Shallow Copy using the Spread Operator
// Original object
const book = {
  title: 'JavaScript Guide',
  author: 'John Doe',
  publisher: {
    name: 'Tech Books',
    year: 2020
  }
};

// Shallow copy using the spread operator
const bookCopy = { ...book };

// Modify the nested object in the copied object
bookCopy.publisher.year = 2023;

console.log(book.publisher.year); // Output: 2023 (affected)
console.log(bookCopy.publisher.year); // Output: 2023

Enter fullscreen mode Exit fullscreen mode
Explanation:

The spread operator ({...book}) creates a shallow copy of the object. However, since publisher is a nested object, both the original and the copied object share the same reference for the publisher object.

Example 3: Shallow Copy with Arrays using the Spread Operator
// Original array
const colors = ['red', 'green', 'blue'];

// Shallow copy using the spread operator
const colorsCopy = [...colors];

// Modify an element in the copied array
colorsCopy[0] = 'yellow';

console.log(colors); // Output: ['red', 'green', 'blue']
console.log(colorsCopy); // Output: ['yellow', 'green', 'blue']

Enter fullscreen mode Exit fullscreen mode
Explanation:

In this case, the spread operator creates a shallow copy of the array. Since the array doesn't contain any nested objects or arrays, changes to the copied array don’t affect the original.

Example 4: Shallow Copy with Arrays using Slice
// Original array
const numbers = [1, 2, [3, 4]];

// Shallow copy using slice method
const numbersCopy = numbers.slice();

// Modify the nested array in the copied array
numbersCopy[2][0] = 99;
numbersCopy[1] = 12

console.log(numbers); // Output: [1, 2, [99, 4]
console.log(numbersCopy); // Output: [1, 12, [99, 4]

Enter fullscreen mode Exit fullscreen mode
Explanation:
  • The shallow copy with .slice() only copied the references for the nested arrays.
  • Modifying the nested array (numbersCopy[2][0] = 99) affected both numbers and numbersCopy because they share the same reference to the nested array.
  • Modifying a non-nested element (numbersCopy[1] = 12) only affected numbersCopy, not numbers, because it is a primitive value (non-reference type).

Thus, the shallow copy mechanism with .slice() works at the top level for the array but does not fully isolate nested objects or arrays.

Example 5: Shallow Copy with Objects Containing Arrays
const config = {
  theme: 'dark',
  colors: ['red', 'green'],
};

// Shallow copy using Object.assign()
const configCopy = Object.assign({}, config);

// Modify the array in the copied object
configCopy.colors[0] = 'yellow';
config.theme = "light"

console.log(config); // Output: {theme: 'light', colors: ['yellow', 'green']}
console.log(configCopy); // Output: {theme: 'dark', colors: ['yellow', 'green']}
Enter fullscreen mode Exit fullscreen mode
Explanation:
  • configCopy.theme remains 'dark' because theme is a primitive, and the shallow copy copied the value, not the reference.
  • configCopy.colors still points to the array ['yellow', 'green'], but this change was due to the shared reference between config and configCopy (they both point to the same array).
  • Shallow copy means that the top-level properties are copied, but for reference types (arrays, objects), only the reference is copied, not the actual values.
Example 6: Shallow Copy with Arrays Containing Objects
// Original array containing objects
const products = [
  { name: 'Laptop', price: 1000 },
  { name: 'Phone', price: 500 }
];

// Shallow copy using slice
const productsCopy = products.slice();

// Modify the object in the copied array
productsCopy[0].price = 1200;

console.log(products[0]); // Output: {name: 'Laptop', price: 1200}
console.log(productsCopy[0]); // Output: {name: 'Laptop', price: 1200}

Enter fullscreen mode Exit fullscreen mode
Explanation:

Since the products array contains objects, and slice() creates a shallow copy, both products and productsCopy refer to the same object for each element in the array. Changing the price in the copied array also affects the original array.

2.Deep Copy

A Deep Copy creates a completely independent copy of the object, and recursively copies all nested objects and arrays, meaning that changes to the deep copy will not affect the original object and vice versa. This ensures that changes made to one object do not affect the others. Each object is stored in a separate memory location, making them entirely independent.

Example:
// Original Object
const original = {
  name: "John",
  age: 30,
  address: {
    city: "New York",
    zip: "10001"
  }
};

// Deep copy using JSON methods
const deepCopy = JSON.parse(JSON.stringify(original));

// Modify the nested object in the deep copy
deepCopy.address.city = "Los Angeles";

console.log(original.address.city); // Output: "New York"
console.log(deepCopy.address.city); // Output: "Los Angeles"
Enter fullscreen mode Exit fullscreen mode
Explanation:
  • JSON.stringify() converts the object into a JSON string.
  • JSON.parse() parses the string back into a new object.
  • This creates a new, independent object where all nested objects are copied, and any modifications to the deep copy do not affect the original object.

Important Differences:

Differences

Deep Copy with Arrays:
// Original Array
const originalArray = [1, 2, [3, 4]];

// Deep copy using JSON methods
const deepCopyArray = JSON.parse(JSON.stringify(originalArray));

// Modify the nested array
deepCopyArray[2][0] = 99;
deepCopyArray[1] = 12

console.log(originalArray); // Output: [1, 2, [3, 4]
console.log(deepCopyArray); // Output: [1, 12, [99, 4]
Enter fullscreen mode Exit fullscreen mode
Explanation:
const deepCopyArray = JSON.parse(JSON.stringify(originalArray));
Enter fullscreen mode Exit fullscreen mode
JSON.stringify(originalArray):
  • This converts the entire originalArray into a JSON string. The nested array [3, 4] is also converted to its JSON representation (a string representation).
JSON.parse():
  • The JSON.parse() method takes the JSON string and converts it back into a new object or array.
  • The key point here is that nested objects (like the array [3, 4]) are also deep-copied, not just the top-level array.
  • As a result, deepCopyArray is an entirely new array with a new reference, and the nested array [3, 4] is also a new reference in deepCopyArray. This is the key difference between deep copy and shallow copy.
deepCopyArray[2][0] = 99;
Enter fullscreen mode Exit fullscreen mode
  • Here, deepCopyArray[2] refers to the nested array [3, 4], which is a new, independent array from the one in originalArray.
  • We change the first element of this nested array to 99. This does not affect originalArray because the nested arrays are deeply copied.
originalArray: [1, 2, [3, 4]]
Enter fullscreen mode Exit fullscreen mode
  • This remains unchanged because we performed a deep copy, meaning the original array and the copied array are completely independent, including their nested arrays.
deepCopyArray: [1, 12, [99, 4]]
Enter fullscreen mode Exit fullscreen mode
  • This reflects the changes we made:
  • The second element was changed from 2 to 12.
  • The first element of the nested array was changed from 3 to 99.

Caveats:

  • Using JSON.parse(JSON.stringify()) for deep copying has limitations:
  • It cannot copy functions, undefined, RegExp, Date, or circular references.
  • It might not preserve special object types (e.g., Map, Set, or Date).

For these cases, libraries like Lodash provide more robust deep copying utilities (e.g., _.cloneDeep()), which handle these edge cases more gracefully.

  • Shallow Copy is faster but links to nested objects, meaning changes to nested structures will reflect in both the original and the copy.
  • Deep Copy is slower but creates a fully independent copy, including all nested objects, which makes it more suitable when you need complete isolation between the original and the copied object.

Top comments (0)