Deep vs Shallow Copy - with Examples
Tags: javascript, webdev, learning, beginners
Published: 2019-07-24 12:12:41

---
title: Deep vs Shallow Copy - with Examples
published: true
description: The spread operator is a great piece of syntax, but it produces shallow copies. What exactly does that mean? And when does it matter?
tags: javascript, webdev, learning, beginners
cover_image: https://thepracticaldev.s3.amazonaws.com/i/tuag1l4a6uubdf9tcllc.jpg
canonical_url: https://tenmilesquare.com/deep-vs-shallow-copy-with-examples/
---

I wrote a post a couple of weeks back about the spread operator. 
{% link https://dev.to/laurieontech/5-uses-for-the-spread-operator-b9i %}
I noted that you could use it to copy both arrays and objects. However, there was one thing I didn't mention (and should have).

These copies are "shallow". That means that they copy all of the values in the original object. However, if those values are references to other data structures, things get a bit tricky. 

I figured the best way to illustrate this was to show a bunch of different examples! Hopefully, this will help explain the potential benefits (and limitations) of the way the spread operator copies.

> Note that none of these examples include circular references or repeated keys, etc. There are a number of different problems you can encounter, but we're focused on the "ideal" use cases.


# Arrays

This is a straight forward example of copying a flattened array.

```javascript
let arr = [ 1, 2, 3 ]
let copy = [...arr]
arr.push(4)
// arr is [ 1, 2, 3, 4 ]
// copy is [ 1, 2, 3 ]
```
If we add an element to `arr`, `copy` is unaffected. The same would be true of `arr` if we added an element to `copy`.

Now, what happens if our array includes an element that's an object?

```javascript
let arr = [ 1, 2, {'a': 3} ]
let copy = [...arr]
arr[2]['a'] = 5
// arr is [ 1, 2, {'a': 5} ]
// copy is [ 1, 2, {'a': 5} ]
```
We can still use the spread operator to copy. However, this introduces some potentially problematic behavior. If we change the contents of the object, it affects both the original array and the copy. The object is copied by reference, so it is shared by both `arr` and `copy`.

What about a multi-dimensional array?

```javascript
let arr = [ 1, 2, [3, 4] ]
let copy = [...arr]
arr[2][0] = 4
// arr is [ 1, 2, [ 4, 4 ] ]
// copy is [ 1, 2, [ 4, 4 ] ]
```
This ends up being the same example as the one above. The array is copied by reference and thus shared by both `arr` and `copy`.

So multi-dimensional arrays can't be changed? Well, not exactly.

```javascript
let arr = [ 1, 2, [3, 4] ]
let copy = [...arr]
arr[2] = [ 1, 2 ]
// arr is [ 1, 2, [ 1, 2 ] ]
// copy is [ 1, 2, [ 3, 4 ] ]
```

In this example, even though we have a multi-dimensional array, we're altering it at the top level. So that only affects `arr` and not `copy`. Even though the `[3,4]` was shared, a new array `[1,2]` was created and referenced by `arr` instead. So we're not making any changes to the contents of `[3,4]`, we're only removing the reference to it in `arr`.

# Objects

Let's look at how this behavior affects objects. This first example shows what happens when copying a flat object.

```javascript
let obj = {a:1, b:2, c:3}
let copy = {...obj}
obj['d'] = 4
// obj is {a:1, b:2, c:3, d:4}
// copy is {a:1, b:2, c:3}
```
As with our array, these two objects are unique clones of each other.

What about a nested object?

```javascript
let obj = {a:1, b:2, c: {a:1}}
let copy = {...obj}
obj['c']['a'] = 5
// obj is {a:1, b:2, c: {a:5}}
// copy is {a:1, b:2, c: {a:5}}
```
Again, we see similar behavior to our array examples up top. The nested object is "shared" and any changes to it will be manifested in both top level objects, `obj` and `copy`.

# So what does this all mean?

As it turns out, "deep copy" is entirely based on whether or not your original structure is more than one level deep. If it's a flattened array, or a flat object structure, the spread operator works just fine for creating a clone.

The "problem" arises if you're referencing another data structure inside your array or object. Those are copied by reference, and changes to them affect all "copies".

# How to get a deep copy

So what happens if you want to "deep copy"? Well, you don't want the spread operator!

For a multi-dimensional array you can do this.

```javascript
let arr = [ 1, 2, [3, 4] ]
var copy = JSON.parse(JSON.stringify(arr))
copy[2][0] = 1
// copy is [ 1, 2, [ 1, 4 ] ]
// arr is [ 1, 2, [ 3, 4 ] ]
```

Even if the array references an object it will work! 

```javascript
let arr = [ 1, 2, {'a': 3} ]
var copy = JSON.parse(JSON.stringify(arr))
arr[2]['b'] = 4
// arr is [ 1, 2, { a: 3, b: 4 } ]
// copy is [ 1, 2, { a: 3 } ]
```

# Conclusion
Deep and shallow copies can be a confusing concept if you're always working with flattened data structures. Hopefully, these examples allow you to better understand what those terms mean.

If you're looking for other content like this check out the posts below.

{% link https://dev.to/laurieontech/3-powerful-examples-of-destructuring-assignment-jlf %}
{% link https://dev.to/laurieontech/introducing-object-fromentries-1d5l %}
{% link https://dev.to/laurieontech/let-s-loop-for-in-vs-for-of-4loh %}