Why Immutability is important in JavaScript?
Tags: javascript, functional, objects, arrays
Published: 2021-05-07 22:54:27

---
title: Why Immutability is important in JavaScript?
published: true
description: 
tags: javascript, functionalprogramming, objects, arrays
//cover_image: https://direct_url_to_image.jpg
---

In JavaScript, Primitive data types (numbers, strings, etc) are immutable but when it comes to objects and arrays they are mutable, please do not think that if you declare your objects and arrays with `const` it will be `constant` which is unchangeable: 

```js
const obj = {
  a: "apple"
}
const updatedObj = obj
updatedObj.a = "banana"
console.log(obj.a) // "banana'
``` 

As you can see when we update `updatedObj`'s value, it updates the original object variable `obj` as well. The reason behind it, objects copy `by reference`, which means when we do `const updatedObj = obj` `updatedObj` is referencing/pointing to `obj`'s memory address, so if we update the `updatedObj` we update `obj` because they are pointing the same value. But in the case of primitive data types (numbers, strings, boolean, undefined, etc) is the opposite. 

> All primitives are immutable, i.e., they cannot be altered. It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned a new value, but the existing value can not be changed in the ways that objects, arrays, and functions can be altered. ~ MDN

Here we can see examples where strings and numbers are not changing.

```js
const num = 39
let updatedNum = num

updatedNum = 45
console.log(num) // 39

const str = "lion"
let updatedStr = str

updatedStr = "tiger"
console.log(str) // "lion"
```

Why do we care about immutability? If JavaScript was built this way then there must be a reason. Yes, it's because JavaScript is a multiparadigm language you can use it as OOP, you can use it as FP (functional programming).
Functional programming embraces immutability and heavily practices [persistent data structure](https://en.wikipedia.org/wiki/Persistent_data_structure). And new libraries like React and Redux take the advantages of immutability, like in Redux, `store` is one giant, plain JS object,  immutable one and this gave the possibility for `redux time travel` where you can see the previous states/changes or in React you can check the previous values of your local states, they all come from the object immutability.

Here is a simple example of creating an immutable object in JS:

```js
const obj = {
  a: "apple"
}
const updatedObj = Object.assign({}, obj)
updatedObj.a = "banana"

console.log(obj.a) // "apple"
console.log(updatedObj.a) // "banana"
``` 
Now we do not mutate our original object `obj`.

> We will have more practical examples on "How not to mutate your objects and arrays" in the next articles.

> [More about Object.assign()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)

You might ask a question 🙋‍♂️ , "Wait if we do not mutate our object value? Then that must be lots of memory consumptions? " ~ You are not wrong!

That's where comes `structural sharing`,  you don't want to `deep copy` the object but `shallow copy` it. Just like `git` does not copy your whole versions of your code but shares the files that are not changed with the previous commit.  

`Object.assign()` method does `shallow copying`. But there is one downside to it, if you have nested object properties, they will not be immutable. 

```js
const obj = {
  a: "apple",
  b: {
    c: "lemon"
  }
}
const updatedObj = Object.assign({}, obj)
updatedObj.a = "mango"
updatedObj.b.c = "banana"

console.log(obj.a) // "apple"
console.log(obj.b.c) // "banana"
```

> `b: { c: "lemon" }` is not immutable here as it's nested property, we will see examples of how to make objects and arrays immutable including nested (complex structures) ones as well.

So `shallow copying` will not take lots of memory consumptions.

### Immutable Objects

1. Using `Object.assign()`

```js
let obj = {
  a: "apple"
}
let updatedObj = Object.assign({}, obj)
updatedObj.a = "banana"

console.log(obj.a) // "apple"
console.log(updatedObj.a) // "banana"
``` 

2. Using `Object Spread Operators`:

```js
 let obj = {
  a: "apple"
}
let updatedObj = { ...obj }
updatedObj.a = "banana"

console.log(obj.a) // "apple"
console.log(updatedObj.a) // "banana"
```
`Spread Operators` are new ES6 syntax, similar to `Object.assign()` method, it does shallow copying.

For complex data structure:

```js
let obj = {
  a: "apple",
  b: {
     c: "lemon"
  }
}
let updatedObj = {...obj, b: { ...obj.b } };
updatedObj.a = "banana"
updatedObj.b.c = "peach"

console.log(obj.a) // "apple"
console.log(obj.b.c) // "lemon"
console.log(updatedObj.a) // "banana"
console.log(updatedObj.b.c) // "peach"
```

If you have nested object properties `let updatedObj = {...obj, b: { ...obj.b } };` you can do nested spread with the property name.

### Immutable Array

1.`Array Spread Operators`

```js
let arr = [1, 2, 3, 4]
let updatedArr = [...arr]
updatedArr[2] = 5

console.log(arr[2])// 3
console.log(updatedArr[2])// 5
```

Array spread operators are the same as object spread operator, actually they are spread operators [learn more here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax).

2.Using `slice()` method:

```js
let arr = [1, 2, 3, 4]
let updatedArr = arr.slice(0, arr.length);
updatedArr[2] = 5

console.log(arr[2]) // 3
console.log(updatedArr[2]) // 5
console.log(updatedArr) // [1, 2, 5, 4]
```

`slice()` cuts the array from the index (first argument) until the index you want (second argument), but it won't affect the original array. There is `splice()` array method, it's the opposite of `slice()` it changes the content of the original array [learn more on slice here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice), [learn more on splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice).

3.Using `map()`, `filter()`:

```js
let arr = [1, 2, 3, 4]

let updatedArr = arr.map(function(value, index, arr){
  return value;
});
updatedArr[2] = 5

console.log(arr[2]) // 3
console.log(updatedArr[2]) // 5
console.log(updatedArr) // [1, 2, 5, 4]
```

`map()` returns a new array, takes a callback function as an argument and calls it on every element of the original array. Callback function takes `value`(current iterated value), `index` (current index), `array`(original array) arguments, all of them are optional [learn more here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).

`filter()`
```js
let arr = [1, 2, 3, 4]

let updatedArr = arr.filter(function(value, index, arr){
  return value;
});
updatedArr[2] = 5

console.log(arr[2]) // 3
console.log(updatedArr[2]) // 5
console.log(updatedArr) // [1, 2, 5, 4]
```
`filter()` and `map()` works the same way [learn more here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter).

>They both return a new array. `map()` returns a new array of elements where you have applied some function on the element so that it changes the element. `filter()` returns a new array of the elements of the original array (with no change to the elements). `filter()` will only return elements where the function you specify returns a value of true for each element passed to the function.

There is one more method for array `reduce()`, it will not return new array, but it will do immutable operations on an original array.

```js
let arr = [1, 2, 3, 4];
// 1 + 2 + 3 + 4
const reducer = (accumulator, currentValue) => accumulator + currentValue;

let updatedArr = arr.reduce(reducer)
console.log(updatedArr) // 10
```

`reduce()` could be confusing at the beginning, but I will try to explain as simply as possible. Let's look at the example below:

```js
let sum = 0;
let i = 0;
while (i<arr.length){
  sum+=arr[i]; // 1 + 2 + 3 + 4
  i++;
}

console.log(sum) // 10
```

It just a loop that sums all the values of an array. We are trying to do the same thing with `reduce()`.

`reduce()` takes `reducer` callback which is a function takes 4 arguments, `accumulator`, `currentValue`, `currentIndex`, `originalArray`. Accumulator saves the value which is returned from last iteration, just like `sum` variable in our loop example, current value is `arr[i]`. That's `reduce` [learn more here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce). 

I hope 🤞 it all makes sense.

Extra Resources:

[This answer here gives a great explanation on "why is immutability important?"](https://stackoverflow.com/a/34385684/9361910), 

[Structural sharing](https://dev.to/viebel/structural-sharing-with-7-lines-of-javascript-2dnh#:~:text=What%20is%20structural%20sharing%3F,the%20files%20on%20each%20commit.), 

[More on immutable methods of array and object](https://medium.com/@joomiguelcunha/learn-map-filter-and-reduce-in-javascript-ea59009593c4)