ミュータブルとイミュータブル

## はじめに
```React```では、```イミュータブル```な操作を必要とされることが多いですが、そもそも```ミュータブル・イミュータブル```についていまいち理解していなかったのでまとめます。

## Javascriptのデータ型
Javascriptのデータ型は```primitive```と```object```があります。
```mermaid
classDiagram
    class primitive{
        string
        number
        bigint
        boolean
        undefined
        symbol
        null
    }
    class object{
        object
        array
        date
    }   
```
```primitive```はイミュータブルで、```object```はミュータブルです。
```ミュータブル```は```変更可能```を意味し、イミュータブルは```変更不可能```を意味します。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Data_structures

https://developer.mozilla.org/ja/docs/Glossary/Mutable

```primitive```の場合は```イミュータブル```であるため、下記のようにコピーをしてその値を変更してもコピー元に対して影響を与えることはありません。
```javascript
    let a = "hello"
    let b = a
    b = "hola"
    console.log(a) // => "hello"
    console.log(b) // => "hola"
```
反対に```object```の場合は```ミュータブル```であるため、コピー元にまで影響が出てしまいます。
```javascript
    const objectOne = {
        first_name: "hello",
        last_name: "world"
    }

    const objectTwo = objectOne
    objectTwo.first_name = "hola"
    
    console.log(objectOne) // => {first_name: "hola", last_name: "world"}
    console.log(objectTwo) // => {first_name: "hola", last_name: "world"}
```
Reactで```イミュータブル```な操作をするためには、```変数もしくは定数```に```primitive```を代入することと、```object```を代入することの違いを理解する必要があります。

## オブジェクトのコピー
```javascript
    const objectOne = {
        first_name: "hello",
        last_name: "world"
    }

    const objectTwo = objectOne
    objectTwo.first_name = "hola"
    
    console.log(objectOne) // => {first_name: "hola", last_name: "world"}
    console.log(objectTwo) // => {first_name: "hola", last_name: "world"}
```
上記の例のようにオブジェクトのコピーをした状態を図に表すと、以下のようになります。
```mermaid
    flowchart LR
    objectOne --> object
    object --> hello
    object --> world
    objectTwo --> object
```
```objectOne```と```objectTwo```は同じオブジェクトを参照している状態であるため、```ミュータブル```な操作になります。

## 新しいオブジェクトを作成してコピーする
```javascript
    const objectOne = {
        first_name: "hello",
        last_name: "world"
    }
    
    const objectTwo = {...objectOne}
    objectTwo.first_name = "hola"
    
    console.log(objectOne) // => {first_name: "hello", last_name: "world"}
    console.log(objectTwo) // => {first_name: "hola", last_name: "world"}
```
上記のように[スプレッドオペレーター](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax)を用い、新しいオブジェクトを作成してからコピーした際の状態を図で表すと以下のようになります。この場合は、それぞれが異なるオブジェクトを参照しているため、```イミュータブル```な操作になります。
```mermaid
    flowchart LR
    objectOne --> object
    object --> hello
    object --> world
    objectTwo --> object'
    object' --> hello
    object' --> world
```
```objectTwo.first_name = "hola"```のように変更した際の状態は下記のようになります。
一方に変更を加えても他方に影響を与えることはありません。
```mermaid
    flowchart LR
    objectOne --> object
    object --> hello
    object --> world
    objectTwo --> object'
    object' --> hola
    object' --> world
```

## 2次元以上でイミュータブルな操作をする
ReactでTodoリストを作るときなどは、以下のような要素がオブジェクトの配列を```state```として持つことが多いと思います。
オブジェクトがネストしている状態なので、```ミュータブル```な操作をしてしまいバグらせることが多いです。
```json
    [
        {
          "id": "number",
          "content": "string"
        }
    ]
```
```javascript
    const todo = [
        {
          id: 1,
          content: "content1",
        },
        {
          id: 2,
          content: "content2",
        },
        {
          id: 3,
          content: "content3",
        }
      ]
```
具体例として上記のような配列で、最初の要素のcontentを変更する場合を考えます。
```javascript
    const copyTodo = todo.slice()
    copyTodo[0].content = "content4"
    console.log(todo)
        // => [{id: 1, content: 'content4'}, {id: 2, content: 'content2'}, {id: 3, content: 'content3'}
    console.log(copyTodo)
        // => [{id: 1, content: 'content4'}, {id: 2, content: 'content2'}, {id: 3, content: 'content3'}
```
```slice```を使ってコピーした配列に変更を加えた場合、コピー元にも変更が及んでしまっています。これでは```ミュータブル```な操作です。
このときの状態を図に表すと以下のようになります。
```mermaid
    flowchart LR
    todo --> Array
    Array --> object
    object --> id
    object --> content
    copyTodo --> Array'
    Array' --> object
```
```イミュータブル```な操作にするには下記のような状態にしたいです。
```mermaid
flowchart LR
todo --> Array
Array --> object
object --> id
object --> content
copyTodo --> Array'
Array' --> object'
object' --> id
object' --> content
```
以上を踏まえると、```イミュータブル```な操作にするには下記のようなコードになります。
```javascript
    const copyTodo = todo.map((preObject) => {
        return {...preObject}
    })
    copyTodo[0].content = "content4"
    console.log(todo)
        // => [{id: 1, content: 'content1'}, {id: 2, content: 'content2'}, {id: 3, content: 'content3'}
    console.log(copyTodo)
        // => [{id: 1, content: 'content4'}, {id: 2, content: 'content2'}, {id: 3, content: 'content3'}
```



## なぜイミュータブルである必要があるのか

https://www.toptal.com/react/react-redux-and-immutablejs

>Immutable.js allows us to detect changes in JavaScript objects/arrays without resorting to the inefficiencies of deep equality checks, which in turn allows React to avoid expensive re-render operations when they are not required. This means Immutable.js performance tends to be good in most scenarios.




## 参考にしたサイト
https://ja.javascript.info/object-copy

https://justjavascript.com/

https://beta.reactjs.org/learn/updating-objects-in-state

https://blog.logrocket.com/immutability-react-should-you-mutate-objects/

https://zenn.dev/sprout2000/books/76a279bb90c3f3/viewer/chapter06