Deep vs Shallow Copy in JavaScript

In JavaScript, when you're dealing with objects and arrays, copying them isn't as straightforward as with primitive types like strings or numbers.

Understanding deep and shallow copying will help you in scenarios where you need to duplicate objects or arrays without altering the original data unintentionally.

Shallow Copy

A shallow copy creates a new object or array and copies the references of the original elements.

This means that the new object or array holds references to the same underlying elements as the original one.

If the elements are primitive types, a shallow copy is sufficient because changes made to the copied elements won't affect the original ones. However, if the elements are objects or arrays themselves, modifying them within the copied structure will reflect in the original structure as well.

For example

const originalArray = [[1], [2], [3]];
const shallowCopy = [...originalArray];
shallowCopy[0].push(4);

console.log(originalArray); // Output: [[1, 4], [2], [3]]

In JavaScript, you can create a shallow copy using various methods:

1. Spread syntax (...)

const originalArray = [1, 2, 3];
const shallowCopy = [...originalArray];

2. Array.slice() method:

const originalArray = [1, 2, 3];
const shallowCopy = originalArray.slice();

3. Object.assign() (for objects):

const originalObj = { a: 1, b: 2 };
const shallowCopy = Object.assign({}, originalObj);

Deep Copy

A deep copy, on the other hand, creates a completely new object or array and recursively copies all the elements within it.

This means that the new object or array and all its nested elements are independent of the original structure. Changes made to the copied structure won't affect the original one, and vice versa.

For example

const originalArray = [[1], [2], [3]];
const deepCopiedArray = deepCopy(originalArray);
deepCopiedArray[0].push(4);

console.log(originalArray); // Output: [[1], [2], [3]]

Deep copying is more complex and typically requires custom logic, especially when dealing with nested objects or arrays. You can achieve deep copying using various techniques:

1. Recursion

function deepCopy(obj) {
  if (typeof obj !== "object" || obj === null) {
    return obj;
  }
  let copy = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key]);
    }
  }
  return copy;
}

2. Using libraries like lodash

const lodash = require("lodash");
const originalArray = [{ a: 1 }, { b: 2 }];
const deepCopy = lodash.cloneDeep(originalArray);

Get my free, weekly JavaScript tutorials

Want to improve your JavaScript fluency?

Every week, I send a new full-length JavaScript article to thousands of developers. Learn about asynchronous programming, closures, and best practices — as well as general tips for software engineers.

Join today, and level up your JavaScript every Sunday!

Thank you, Taha, for your amazing newsletter. I’m really benefiting from the valuable insights and tips you share.

- Remi Egwuda