JavaScript おじさんが教える本当の Modern JavaScript 入門 2 「const, immutable, functional programming」

![n8085ba48df1cb670.jpg](https://qiita-image-store.s3.amazonaws.com/0/240885/55ddf7bd-8493-92bc-d4a0-6226caaeddac.jpeg)

## シリーズ概要
### [Phase 1 のまとめ](https://qiita.com/superyusuke/items/948d2a084f87eaa3f9c2)

- Parcel で module system が使えるようになった。
- Parcel で Babel の処理をしてくれるので、ES2015+ syntax で JS を書くことができるようなった。
- Parcel が勝手に JSX も処理してくれるので React コンポーネントを JSX で書けるようになった。
- Prettier でコードが成形できるようになった。

### Phase 2
モダンなパラダイムで JavaScript を書く

- var, let を書かないで、ほぼ全部 const にする
- immutable にする
- そのためには functional programming に則っていく必要あり。
map, reduce 等をうまく使う。

### Phase 3 の展望
非同期処理をモダンに書く

- Callback の根絶
- Promise の理解
- async / await を使う
- redux/vuex 関係でも async/await を使う

### Phase 4 の展望
Virtual DOM を用いた View ライブラリの活用

- ReactJS
- VueJS
- Redux/Vuex

## モダンなパラダイムで JavaScript を書く

- 全て const を使う(くらいの気持ちで)
- Immutable にする(Object の property, Array の要素を変更しない)
- Functional Programming を意識する

Immutable にすることを意識すれば、結果として上記三つを満たすことになる。

## const を基本的に使う

- 全て const でかく(くらいの気持ちで)
- var は使うケースはないと考えていい
- let もほぼほぼ使わない

変数を宣言する場合には、基本的に `const` を使用する。`const` は再代入を受け付けない。 

### 関数の場合

https://codesandbox.io/s/jj2lklyk7w

関数を再代入する必要があるケースはほぼない。そのため `const` を使う。
もし関数を再代入する必要があるとすれば、その構造自体を再検討する必要がある。

```js
// 関数宣言 (function declaration) を使用した場合
// 関数の巻き上げ (function hoisting) が起きてしまう
// これはしない方がいい
// 可読性が低いため

func1()

function func1() {
  console.log('func1')
}

// 関数式(function expression) で定義した場合
// 関数の巻き上げは起きない
// 望ましい
try {
  func2()
} catch (err) {
  console.error(err.message)
}

var func2 = function() {
  console.log('func2')
}

// (特殊なケースを除けば)
// 関数を再代入することは避けた方がいいので
// 再代入を禁止する const を使用する方が良い
// また arrow function を使った方がよい
const func3 = () => {
  console.log('func4')
}

func3()

// async を使いたい場合には、
// 以下のように書けばいい
const promiseFunc = val => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(val)
    }, 1000)
  })
}

const func5 = async () => {
  const val = await promiseFunc('start promise')
  console.log(val)
}

func5()

```

### 配列に push していくパターンもやめる
(どちらかというと後ほど取り上げる immutable のテーマだが)

https://codesandbox.io/s/j4ollpp2mw

```js
// よくみるがあまり良くない例
// からの配列を宣言しておいて、後からそれに追加するパターン
var array1 = [1, 2, 3, 4]
var array2 = []

for (var i = 0; i < array1.length; i++) {
  array2.push(array1[i] + i)
}

console.log(array2)

// map を使えば全て const で宣言できる
const array3 = [1, 2, 3, 4]
const array4 = array3.map((o, index) => o + index)

console.log(array4)
```
### Object の場合

(これも配列の場合と同じく、immutable が主テーマだが)

```js
const obj1 = { name: 'nakanishi', id: 1 }

// property を書き換える場合には次のようにする
// 実際には書き換えているのではなく、新しいオブジェクトを作成している
const obj2 = { ...obj1, name: 'sasaki' }

console.log(obj1, obj2)
```

## Immutable にする

https://codesandbox.io/s/xrp6lqz57w

- Object のプロパティを変更しない
- Array の要素を変更しない
- 新しい object, array を生成する

```js
// object を deep freeze させる
// => mutation が起きる場合、エラーを吐く
import deepFreeze from 'deep-freeze'

// object の場合
const obj1 = { name: 'nakanishi', id: 1 }
deepFreeze(obj1)

// property を書き換える場合には次のようにする
// 実際には書き換えているのではなく、新しいオブジェクトを作成している
const obj2 = { ...obj1, name: 'sasaki' }

console.log(obj1, obj2)

// deepFreeze させているので、
// property を書き換えるとエラーが出る
try {
  obj1.name = 'sasaki'
} catch (err) {
  console.error(err.message)
}

// 配列の場合
const array1 = []
deepFreeze(array1)

// 配列の要素を書き換える場合には次のようにする
// 実際には書き換えているのではなく、新しい配列を作成している
const array2 = [...array1, 'test']
console.log(array1, array2)

try {
  // deepFreeze させているので、
  // 配列の要素を書き換えるとエラーが出る
  array1.push('test')
} catch (err) {
  console.error(err.message)
}

const array3 = [1, 2, 3]

try {
  // deepFreeze させているので、
  // 配列の要素を書き換えるとエラーが出る
  array1[0] = 'test'
} catch (err) {
  console.error(err.message)
}

// Object の property を削除する方法
const person = {
  name: 'John',
  password: '123',
  age: 28,
}

deepFreeze(person)

// 特定の key を削除する関数
const delteObjectKey = (object, deleteTargetKey) => {
  return Object.keys(object).reduce((obj, key) => {
    if (key !== deleteTargetKey) {
      return { ...obj, [key]: person[key] }
    }
    return obj
  }, {})
}

// person オブジェクトから age という key を削除する
const newPerson = delteObjectKey(person, 'age')

console.log(newPerson)

try {
  // deepFreeze させているので、
  // プロパティを削除するとエラーが出る
  delete person.age
} catch (err) {
  console.error(err.message)
}
```

## Functional Programming を意識する
map, reduce 等をうまく使う。
詳しくは手前味噌ですみませんが、次の記事を参照してください。
[JavaScript おじさんが教える ES2015+ と関数型プログラミング 1](https://qiita.com/superyusuke/items/50aaf42a75618d9c3364)

## まとめ

以下の三つを守って、可読性が高く、変更に強い JavaScript を書く。

- 全て const を使う(くらいの気持ちで)
- Immutable にする(Object の property, Array の要素を変更しない)
- Functional Programming を意識する