Javascript Shallow Copy - what is a Shallow Copy?
Tags: webdev, javascript, typescript, tutorial
Published: 2022-10-22 19:43:42

**Shallow copy** and **deep copy** are terms thrown around in Javascript that can be confusing if you have never heard them before. It is quite common to hear that array methods like [slice](https://fjolt.com/article/javascript-slice) or [filter](https://fjolt.com/article/javascript-filter) make a shallow copy of the original array.


## What is a shallow copy in JavaScript?
**A shallow copy** of an arrays or object is one where they both have the same [reference](https://fjolt.com/article/javascript-by-reference-by-value) in memory. That means that if you change the shallow copy, it **may** change the original copy too. I say **may**, since that is not always the case. 

Let's look at an example using `slice`:

```javascript
let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  

console.log(arrayOne); // [ '⚡️', '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ '🔑' ]
```

Here we have an array, which we then `slice` in the variable `arrayOneSlice`. Both of these arrays have the same reference in memory, since `slice` makes a shallow copy of them. So if we try to update `arrayOneSlice`, it will affect `arrayOne` too, right?

```javascript
let arrayOne = [ '⚡️', '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(2, 3);  

// Update arrayOneSlice
arrayOneSlice[2] = '⚡️'

console.log(arrayOne); // [ '⚡️', '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ '🔑', empty, '⚡️' ]
```

Only, it doesn't - since we used the square bracket notation, Javascript interprets this as putting a new value into the `[2]` position. So only `arrayOneSlice` is updated - and for good reason too. Although '🔑' is at position `[2]` in `arrayOne`, it is in position `[0]` in `arrayOneSlice`. This can give the illusion that these two arrays are copies and act independently of each other - but that's not the case either. Consider the following example: 

```javascript
let arrayOne = [ { items: [ '🔎' ]}, '🔎', '🔑', '🔩' ];
let arrayOneSlice = arrayOne.slice(0, 3);  

// Update arrayOneSlice
arrayOneSlice[0].items = [ '⚡️' ]

console.log(arrayOne); // [ { items: [ '⚡️' ]}, '🔎', '🔑', '🔩' ]
console.log(arrayOneSlice); // [ { items: [ '⚡️' ]}, '🔎', '🔑' ]
```

Here, we updated `arrayOneSlice[0].items`, and its updated on both arrays, since `items` exists on both arrays at the same position, and we didnt assign a new value, but rather used the dot `.` notation to update an existing property. In Javascript, this updates both the original and the copy we made using `slice`.

**The main point** to remember with shallow copies, is that adjusting one can affect the original you are trying to copy - the reference in memory is the same, and the reference points to the values of the array - so you have to be more careful. What you don't want to do is create unexpected behaviour where the original and copy of an array do not update in sync when you expected them to.

## So how do you make deep copies in Javascript?

Javascript has historically had a bit of a problem with **deep copies**. Most methods in Javascript like the [three dots or spread syntax](https://fjolt.com/article/javascript-three-dots-spread-operator), `Object.create()`, `Object.assign()`, and `Array.from()` all make shallow copies. 

**Deep copies** have different references in memory, though, so you don't have to worry about mutating the original when using them. This makes them very useful when we want to avoid that.

Deep copies can be made via serialisation, or a custom script to copy each part of an object or an array into a new one - creating a new reference in memory. For example, this will create a new array in Javascript with a new reference:
```javascript
let myArray = [ 1, 2, 3, 4 ];
let deepCopy = JSON.parse(JSON.stringify(myArray));
```

This is not necessarily the best way to do it though. You can also use the `structuredClone()` function to make a deep copy:
```javascript
let myArray = [ 1, 2, 3, 4 ];
let deepCopy = structuredClone(myArray);
```

Now we have created new arrays with deep copies, we no longer need to worry about messing up the original when we change the copy.

## Conclusion

Shallow copies are quite confusing, and one of the many quirks which Javascript presents. Understanding what they are can save you a lot of headaches when debugging in the future, and using deep copies is a good way to avoid some of these issues.