Explaining shallow / deep copying through acronyms
Tags: javascript, object, explainlikeimfive, ajax
Published: 2019-03-27 23:15:51

> Originally posted at [michaelzanggl.com](https://michaelzanggl.com/articles/shallow-copying-explained-in-simple-terms). Subscribe to [my newsletter](https://michaelzanggl.com/) to never miss out on new content.

To understand shallow / deep copying let's step away from the keyboard for a moment and look at dimensions in General.

In fact, let's take a look at the acronym `ajax`. What does it actually stand for?

> `Asynchronous JSON and XML`.

Wait... so the acronym `ajax` is made up of two more acronyms `JSON` and `XML`.
In other words, the acronym `ajax` has a second dimension of acronyms which makes it a multi dimensional acronym! 😱

So when we unabbreviate `ajax` to `Asynchronous JSON and XML` we only unabbreviate the first dimension, in other words: shallow-unabbreviating. A word that may not yet exist today, but will soon find its way into dictionaries. Notice how the second dimensions `JSON` and `XML` stay untouched. We are merely referencing to these other acronyms.

If we were to deep-unabbreviate `ajax`, this is what we would get:

> Asynchronous JavaScript Object Notation And Extensible Markup Language

Imagine, in the old days, we would have had to write
`$.asynchronousJavaScriptObjectNotationAndExtensibleMarkupLanguage`

Another example of a multi dimensional acronym is the JAM stack.

Shallow-unabbreviated:

> JavaScript API Markup

Deep-unabbreviated: 

> JavaScript Application Programming Interface Markup

---

So let's step away from these rather unfortunately named acronyms and into the code.

```javascript
const ajax = {
  a: 'Asynchronous',
  j: {
    j: 'Java',
    s: 'Script',
    o: 'Object',
    n: 'Notation'
  },
  a2: 'and',
  x: {
    x: 'Extensible',
    m: 'Markup',
    l: 'Language'
  }
}
```

Here we have `ajax` layed out in a two dimensional object.

What happens if we copy this object into another object

```javascript
const obj = ajax
obj.x = null

obj.x //? null
ajax.x //? null
```

This won't work. `obj` will be merely a reference to `ajax`. Changing one will change the other respectively. That's the way objects work in JavaScript.


How about this?

```javascript
const obj = Object.assign({}, ajax) 
// or: const obj = {...ajax}

obj.x = null

obj.x //? null
ajax.x //? { x: 'Extensible', m: 'Markup', l: 'Language' }
```

Nice, we created an actual copy! Or did we...?

```javascript
const obj = Object.assign({}, ajax)

obj.x.l = 'lang'

obj.x.l //? lang
ajax.x.l //? lang
```

Turns out `Object.assign` as well as ES6 spread syntax are merely doing a shallow-copy!

So how can we possibly copy the entire object, i.e. deep-copy?

A rather hackish solution you often see is the following

```javascript
const obj = JSON.parse(JSON.stringify(ajax))
```

While this would work in our example, it would simply remove any methods on the object. It will also not work on maps and sets. 

The sad truth is, JavaScript does not provide such functionality out of the box. You can either create your very own deep copy method or make use of [existing solutions](https://www.npmjs.com/package/deepcopy).

PS. In JavaScript arrays are objects, so everything we talked about also applies to arrays.