※前編はこちらやで。
ハスケル子「引き続き、JavaScriptとElm・・・」
ハスケル子「そしてVue.jsもちょこっと比べてみましょう」
オブジェクト(のようなもの)
JavaScriptのオブジェクト
const takashi = {
displayName: "たかし",
age: 36,
height: 173,
weight: 73
};
ワイ「displayName
とかage
とかが、プロパティいうやつやな」
ワイ「takashi.age
とかすると、プロパティの値にアクセスできんねん」
Elmのレコード
takashi =
{ displayName = "たかし"
, age = 36
, height = 173
, weight = 73
}
ワイ「Elmではレコードいうねんな」
ワイ「JSのオブジェクトとけっこう似てるな」
ワイ「displayName
とかage
とかのことは」
ワイ「フィールドっていうんやな」
ワイ「JSと同じくtakashi.age
って書けばフィールドの値にアクセスできんねん」
オブジェクトのプロパティを更新
JavaScriptのオブジェクト
takashi.age = 37;
takashi.weight = 83;
ワイ「const
で宣言した再代入不可なオブジェクトでも、プロパティは変更できてまうんやな」
Elmのレコード
newTakashi =
{ takashi | age = 37, weight = 83 }
ワイ「Elmでは全ての値が不変やからtakashi.age = 37
みたいな上書きはできひんねん」
ワイ「せやから、1つ歳をとって10Kg太ったnewTakashi
という新しいレコードを作る形になる」
ワイ「元々のtakashi
は36歳のまま、別に存在すんねん」
ドキュメントの書き方
JavaScript (JSDoc)
/**
* @param {Number} num
* @param {String} str
* @return {String}
*/
function displayNumber (num, str) {
return num + str;
}
ワイ「関数の使い方が分かりやすいように」
ワイ「引数や戻り値の型をコメントで書いたりすんねんな」
ワイ「まぁ、実装とズレてても動くから、努力目標やけどな・・・」
Elmの場合は型で表現
displayNumber : Int -> String -> String
displayNumber num str =
String.fromInt num ++ str
ワイ「displayNumber : Int -> String -> String
いうのは」
ワイ「このdisplayNumber
いう関数は」
ワイ「引数としてInt型の値とString型の値を受け取って」
ワイ「戻り値としてString型の値を返す」
ワイ「そんな関数ですよ〜っていう」
ワイ「型注釈いうやつや」
ワイ「しかも、この型注釈で書いた通りに実装せえへんと」
ワイ「ちゃんとコンパイルエラーが出て教えてくれんねん」
ワイ「**TYPE MISMATCH(型の不一致)**です〜、言うてな」
ワイ「つまり、強制力のある注釈や!」
ビューの書き方
Vue.jsの場合(単一ファイルコンポーネント)
<template>
<div class="container">
<button>増やす</button>
<input type="text">
<button>減らす</button>
</div>
</template>
ワイ「ほぼhtmlやな」
ワイ「読みやすいな」
Elmの場合
view model =
div [ class "container" ]
[ button [] [ text "増やす" ]
, input [ type_ "text" ] []
, button [] [ text "減らす" ]
]
ワイ「このdiv
とかbutton
ていうのがタグ名やね・・・?」
ハスケル子「まあそうなんですけど」
ハスケル子「タグ名というより、れっきとしたElmの関数です」
ハスケル子「関数なので───」
joinButton =
button [] [ text "参加する" ]
ハスケル子「───こんな感じで変数に格納すれば」
ハスケル子「それだけでコンポーネントみたいに使えますし」
commonButton buttonText =
button [] [ text buttonText ]
ハスケル子「↑こう、引数としてテキストを受け取る関数にすれば」
ハスケル子「propsを受け取って表示するタイプのコンポーネントもサクッと作れます」
ワイ「おお」
ワイ「コンポーネントも関数そのものやから、コードの中で自然に使えるな」
ハスケル子「そうなんです」
ハスケル子「リスト1の分だけ回してli
要素を生成したい、なんて場合も簡単です」
イベントリスナ登録(のようなもの)
Vue.jsの場合
<button @click="incrementFunc">増やす</button>
<input type="text">
<button @click="decrementFunc">減らす</button>
ワイ「見たままやな」
ワイ「ボタンをクリックするとincrementFunc
かdecrementFunc
という」
ワイ「関数が実行されんねんな」
ワイ「関数はmethods
の中に書いとけばええんや」
Elmの場合
button [ onClick Increment ] [ text "増やす" ]
, input [ type "text" ] []
, button [ onClick Decrement ] [ text "減らす" ]
ワイ「こう書いておけば、このボタンをクリックした時に・・・?」
ハスケル子「Increment
またはDecrement
というメッセージが生み出されます」
ワイ「メッセージ・・・?」
ワイ「そのメッセージはどこで受け取るん?」
ハスケル子「状態の更新内容を定義するupdate
っていう関数で受け取ります」
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はとってもシンプルなので」
ハスケル子「学習コストが低くて、やめ太郎さんにピッタリです」
ワイ「どういう意味やねん」
ハスケル子「オンラインエディタでさっきのカウンタのサンプルコードを色々いじってみると」
ハスケル子「更に分かると思いますよ」
ワイ「やってみるわ」
ワイ「おおきにやで、ハスケル子ちゃん」
ハスケル子「Vue勉強しててもReact勉強してても」
ハスケル子「副作用を起こさないように、とか」
ハスケル子「外部の状態に依存しない純粋な関数・・・つまり参照透過的な関数を書こう、とか」
ハスケル子「色んなドキュメントに書いてあるんですよ」
ハスケル子「じゃあ、そういう風にしか書けないElmやりゃあいいんですよ」
ワイ「お、おう・・・」
ワイ「前向きに検討するわ・・・」
ワイ「っていうか、今回JSやVueと比較したおかげでElmの文法がかなり分かったから」
ワイ「普通に読み書きできそうやな・・・」
ワイ「やってみるで!」
〜おしまい〜
-
配列みたいなやつやで。 ↩