JavaScriptとElmを比べてみた〜後編・Vue.jsとも比べてみた〜

**※前編は[こちら](https://qiita.com/Yametaro/items/50a2ce2014327f6c8869)やで。**

ハスケル子「引き続き、**JavaScript**と**Elm**・・・」
ハスケル子「そして**Vue.js**もちょこっと比べてみましょう」

## オブジェクト（のようなもの）
### JavaScriptのオブジェクト
```javascript
const takashi = {
    displayName: "たかし",
    age: 36,
    height: 173,
    weight: 73
};
```

ワイ「`displayName`とか`age`とかが、**プロパティ**いうやつやな」
ワイ「`takashi.age`とかすると、プロパティの値にアクセスできんねん」

### Elmのレコード
```elm
takashi =
    { displayName = "たかし"
    , age = 36
    , height = 173
    , weight = 73
    }
```

ワイ「Elmでは**レコード**いうねんな」
ワイ「JSのオブジェクトとけっこう似てるな」
ワイ「`displayName`とか`age`とかのことは」
ワイ「**フィールド**っていうんやな」
ワイ「JSと同じく`takashi.age`って書けばフィールドの値にアクセスできんねん」



## オブジェクトのプロパティを更新
### JavaScriptのオブジェクト
```javascript
takashi.age = 37;
takashi.weight = 83;
```

ワイ「`const`で宣言した再代入不可なオブジェクトでも、プロパティは変更できてまうんやな」

### Elmのレコード
```elm
newTakashi =
    { takashi | age = 37, weight = 83 }
```

ワイ「Elmでは**全ての値が不変**やから`takashi.age = 37`みたいな**上書きはできひんねん**」
ワイ「せやから、1つ歳をとって10Kg太った`newTakashi`という新しいレコードを作る形になる」
ワイ「元々の`takashi`は36歳のまま、別に存在すんねん」


## ドキュメントの書き方
### JavaScript （JSDoc）
```javascript
/**
 * @param  {Number} num
 * @param  {String} str
 * @return {String}
 */
function displayNumber (num, str) {
    return num + str;
}
```

ワイ「関数の使い方が分かりやすいように」
ワイ「引数や戻り値の型をコメントで書いたりすんねんな」
ワイ「まぁ、実装とズレてても動くから、努力目標やけどな・・・」

### Elmの場合は型で表現
```elm
displayNumber : Int -> String -> String
displayNumber num str =
    String.fromInt num ++ str
```

ワイ「`displayNumber : Int -> String -> String`いうのは」
ワイ「この`displayNumber`いう関数は」
ワイ「引数として**Int型**の値と**String型**の値を受け取って」
ワイ「戻り値として**String型**の値を返す」
ワイ「そんな関数ですよ〜っていう」
ワイ「**型注釈**いうやつや」

ワイ「しかも、この型注釈で書いた通りに実装せえへんと」
ワイ「ちゃんとコンパイルエラーが出て教えてくれんねん」
ワイ「**TYPE MISMATCH（型の不一致）**です〜、言うてな」

ワイ「つまり、**強制力のある注釈**や！」

## ビューの書き方
### Vue.jsの場合（単一ファイルコンポーネント）
```vuejs
<template>
  <div class="container">
    <button>増やす</button>
    <input type="text">
    <button>減らす</button>
  </div>
</template>
```

ワイ「ほぼ**html**やな」
ワイ「読みやすいな」

### Elmの場合
```elm
view model =
    div [ class "container" ]
        [ button [] [ text "増やす" ]
        , input [ type_ "text" ] []
        , button [] [ text "減らす" ]
        ]
```

ワイ「この`div`とか`button`ていうのがタグ名やね・・・？」

ハスケル子「まあそうなんですけど」
ハスケル子「タグ名というより、れっきとしたElmの**関数**です」
ハスケル子「関数なので───」

```elm
joinButton =
    button [] [ text "参加する" ]
```

ハスケル子「───こんな感じで変数に格納すれば」
ハスケル子「それだけで**コンポーネントみたいに**使えますし」

```elm
commonButton buttonText =
    button [] [ text buttonText ]
```

ハスケル子「↑こう、引数としてテキストを受け取る**関数**にすれば」
ハスケル子「**props**を受け取って表示するタイプのコンポーネントもサクッと作れます」

ワイ「おお」
ワイ「コンポーネントも関数そのものやから、コードの中で自然に使えるな」

ハスケル子「そうなんです」
ハスケル子「リスト[^1]の分だけ回して`li`要素を生成したい、なんて場合も簡単です」

## イベントリスナ登録（のようなもの）

### Vue.jsの場合

```vuejs
<button @click="incrementFunc">増やす</button>
<input type="text">
<button @click="decrementFunc">減らす</button>
```

ワイ「見たままやな」
ワイ「ボタンをクリックすると`incrementFunc`か`decrementFunc`という」
ワイ「関数が実行されんねんな」
ワイ「関数は`methods`の中に書いとけばええんや」

### Elmの場合
```elm
button [ onClick Increment ] [ text "増やす" ]
, input [ type "text" ] []
, button [ onClick Decrement ] [ text "減らす" ]
```
ワイ「こう書いておけば、このボタンをクリックした時に・・・？」

ハスケル子「`Increment`または`Decrement`という**メッセージ**が生み出されます」

ワイ「**メッセージ**・・・？」
ワイ「その**メッセージ**はどこで受け取るん？」

ハスケル子「**状態の更新内容**を定義する`update`っていう関数で受け取ります」

```elm
update msg model =
    case msg of
        Increment ->
            { model | int = model.int + 1 }
        Decrement ->
            { model | int = model.int - 1 }
```

ハスケル子「`Increment`というメッセージが来たら」
ハスケル子「`model`・・・つまり**Vuex**でいう`store`の`state`みたいなもんですね」
ハスケル子「要は`model`イコール**状態**です」
ハスケル子「その`model`の中の`int`を`1`増加させます」
ハスケル子「メッセージが`Decrement`だった場合は`1`減らす感じですね」
ハスケル子「そして、それによって生成された**新しいmodel**を戻り値として返すって感じです」

ワイ「ほえ〜、新しいmodel、つまり**新しい状態**を返すと」
ワイ「それが**リアクティブ**にビューに反映されるっていうこと？」

ハスケル子「そうです」

ワイ「そうなんやね〜」
ワイ「Elmって、**Vue**とか**React**みたいに**仮想DOM**を内蔵してたんやね」
ワイ「あと**VuexやRedux相当の機能**もか」

ハスケル子「そうです」
ハスケル子「っていうか**Vuex**も**Redux**も、**Elm**の影響を受けてます」
ハスケル子「Elmというか、今みたいな**The Elm Architecture**というパターンの影響ですね」
ハスケル子「しかもElmはとってもシンプルなので」
ハスケル子「学習コストが低くて、**やめ太郎さんにピッタリ**です」

ワイ「**どういう意味やねん**」

ハスケル子「**[オンラインエディタ](https://ellie-app.com/37gVmD7Tm9Ma1)**でさっきの**カウンタ**のサンプルコードを色々いじってみると」
ハスケル子「更に分かると思いますよ」

ワイ「やってみるわ」
ワイ「おおきにやで、ハスケル子ちゃん」

ハスケル子「Vue勉強しててもReact勉強してても」
ハスケル子「**副作用を起こさないように**、とか」
ハスケル子「外部の状態に依存しない純粋な関数・・・つまり**参照透過的な関数を書こう**、とか」
ハスケル子「色んなドキュメントに書いてあるんですよ」
ハスケル子「じゃあ、そういう風にしか書けない**Elmやりゃあいいんですよ**」

ワイ「お、おう・・・」
ワイ「**前向きに検討するわ・・・**」
ワイ「っていうか、今回JSやVueと比較したおかげでElmの文法がかなり分かったから」
ワイ「普通に読み書きできそうやな・・・」
ワイ「**やってみるで！**」

**〜おしまい〜**

[^1]: 配列みたいなやつやで。