Shallow vs Deep Copies

What is the difference between a shallow and deep copy in javascript?

Shallow vs Deep Copies
Photo by Mohammad Rahmani / Unsplash

Ever wondered why when you start to manipulate arrays and objects that somethings your code can completely fly all over the place. Learning what shallow and deep copies are here to the rescue.

When cloning an array or object in JavaScript there are two ways to do this, the first being a shallow copy that will copy the top level of the array or object. For example...

const original = {
  name: 'James'
  age: 26,
  address: {
    line1: 'not telling',
    line2: 'not telling you more'
  }
}

const original2 = ['testing', ['testing2', 'testing3']]

Here we have two const's both the array and the object have a second layer of values. For the first we have the address that can be accessed at original.address.line1, For the second we have an array with an array which can be accessed at original2[1][0].

Now these values are what are considered DEEP values. A SHALLOW value would be the top level values such as original.name or original2[0].

Now that you know the difference you will need to decide how you want to copy the value so that you can manipulate the data with breaking the original.

The most common way to clone the value is by using the spread operator.

const shallowCopy = {...original}
const shallowCopy2 = {...original2}

With this you've now copied the entire object / array but and there's a big but, only the top level has been copied. The secondary layers are still referencing the first layer.

// Object Example
const original = {
  name: 'James',
  age: 26,
  address: {
    line1: 'not telling',
    line2: 'not telling you more'
  }
}

const shallowCopy = {...original}

shallowCopy.name = 'John' 

console.log(original.name) // James

shallowCopy.address.line1 = 'new line 1'

// Even though I edited the shallowCopy above it still changed the original because we only did a shallow copy and the deeper values were still referenced to the original
console.log(original.address.line1) // new line 1


// Array Example
const original2 = ['testing', ['testing2', 'testing3']]

const shallowCopy2 = [...original2]

shallowCopy2[0] = 'testing 4'

console.log(original2[0]) // testing

shallowCopy2[1][0] = 'testing 5' 

// Once again even though we never explicitly changed the original value because we only had a shallow copy it still had references to the original
console.log(original2[1][0]) // testing 5

From the above you can see what it means to do a shallow copy and how that could affect the way you look at coding in the future. Also keep in mind that using the spread operator isn't the only way to make shallow copy you can also use array slice() or concat().

But okay James how do we actually do a deep copy so that we don't have any references to the original. Well... let's dive into that.

const deepCopy = JSON.parse(JSON.stringify(original));

You use JSON.parse and JSON.stringify together that way you turn your entire object into a string and then you parse it back into an object. This will have no references to the original and you can do what you please without worrying about it affecting anything else.

Keep in mind though the performance for deep copies can vary depending on how large the object is and in most cases a shallow copy is going to be just as effective depending on your data structure.

Happy developing!