- 作者: Michael Fogus,和田祐一郎
- 出版社/メーカー: オライリージャパン
- 発売日: 2014/01/18
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (5件) を見る
動機
- yhashimotoのおすすめ書籍
- TypeScriptやES2015~に慣れてしまっているので、JavaScriptの基本を改めて押さえておきたい
- 関数型プログラミングについて本から学んだことがなかった
感想
関数型プログラミングのエッセンスを改めて本で学べてよかった。あとはUnderscore.jsを使って解説が進んでいくので、Underscore.jsについてかなり詳しくなれる笑。
ES5しかりUnderscore.jsしかり、2018年のJavaScriptでは必須ではない要素が多いのも事実だけど、関数型の考えとテクニックをわかりやすいコードで体験できるとても良い本だった。
この次は、「付録 A 世の中の関数型JavaScript」でも紹介されているElmを触ってみたくなった。Introduction · Elm Tutorial を今度やってみようと思う。
読書メモ
1章 関数型JavaScriptへのいざない
関数型プログラミングとは、値を抽象の単位に変換する関数を使用して行うプログラミングであり、それらを使ってソフトウェアシステムを構築することである。
- 関数型のアプローチ: 人間に関するデータの取り扱いに理想的
- オブジェクト指向のアプローチ: 人間をシミュレートする場合に最適
2章 第一級関数と作用的プログラミング
JavaScriptが第一級関数をサポートしているという事実が、関数型プログラミングの実践を後押しします。
- Underscore.jsはいいぞ
3章 JavaScriptにおける変数のスコープとクロージャ
- 関数スコープをシミュレートすることで、thisについての理解が深まる
function strangerIdentity(n) { // intentionally stranger still for(this['i'] = 0; this['i']<n; this['i']++); return this['i']; } strangerIdentity(108); //=> 108 i; //=> 108 // グローバル変数を汚染している strangerIdentity.call({}, 10000); //=> 10000 i; //=> 108 // グローバル変数への汚染は防げたが、このままだとグローバル変数にアクセスできない function f() { this['a'] = 200; return this['a'] + this['b']; } var globals = {'b': 2}; f.call(_.clone(globals)); //=> 202 globals; //=> {'b': 2}
クロージャを一言で表すと、自身が定義されたスコープに存在する外部のバインディングを、そのスコープの実行完了後にも使用するために確保している関数のことです。
- 次はクロージャをシミュレートしてみよう
- 外側の関数で定義された変数を個別に確保しておき、その変数を、返す関数のthisにバインドする
function createWeirdScaleFunction(FACTOR) { return function(v) { this['FACTOR'] = FACTOR; var captures = this; return _.map(v, _.bind(function(n) { return (n * this['FACTOR']); }, captures)); }; } var scale10 = createWeirdScaleFunction(10); scale10.call({}, [5, 6, 7]) //=> [50, 60, 70];
4章 高階関数
- 高階関数の定義
- 第一級データ型である
- 引数として関数をとる
- 関数を戻り値として返す
- 値ではあく、関数を使え
- どのような引数が渡されても常に定数を返す関数を使用する
- 関数型スタイルでは実行ターゲットとなるオブジェクトを引数に取る関数を好む
- 高階関数に渡す引数は返される関数の「設定項目」であると考えてみるとよい
5章 関数を組み立てる関数
- カリー化
- カリー化された関数は、論理定な引数が1つ渡されるたびに新しい関数を返す関数
- 右から左へカリー化することでオプションの引数の個数を固定できるのでオススメ
- カリー化された関数を使用することによって、「流暢な」インターフェイスを持った関数を生成できる
- Haskellでは、関数はデフォルトでカリー化されている
- 部分適用
- カリー化とは異なり、引数の数は必ずしも一つではなく、複数の引数を扱うこともできる
- JavaScriptにおいて、関数が可変長の引数を取ることにより複雑化されてしまうカリー化とは異なり、任意の数の引数の部分適用は関数合成の戦略として合理的と言える
6章 再帰
- 共通の問題のサブセットに単一の抽象を使用する
- 「値は、大きな問題に内包された小さな問題によって組み立てられたものである」
- 可変の状態を隠蔽することができる
- 遅延評価や、無限データ構造の処理を行う手段のひとつ
- 末尾再帰
- 関数内で起こる(終了条件を満たす場合を除いた)最後のアクションが再帰呼び出し
- 末尾再帰による最適化 - Qiita
- Generator
7章 純粋性、不変性、変更ポリシー
- 関数型プログラミングは、ソフトウェアの創造プロセスにまとわりつく複雑さを最小限に抑えるための構築方法を考える手段
- 純粋関数
- 関数自身がコントロールできる範囲外にあるどの変数も変更せず、返さず、そして依存しない
- Ref: Immutable.js
8章 フローベースプログラミング
- チェーン
- 共通の参照をもつメソッドを連続して呼ぶ
- _.chain()
- Promise
- 共通の参照をもつメソッドを連続して呼ぶ
- パイプライン
- 期待されるデータ値が入力されると、非破壊的変換を行い、そして新しいデータを返す
- アクション
- 異なる型の戻り値をもったさまざまな関数を合成するテクニック
- 内部のデータ構造の管理詳細を隠蔽
- Reduxのactionにも通じる?
9章 クラスを使わないプログラミング
- Mixin
- mixinで定義したすべてのメソッドをプロトタイプにコピー
_.extend(Hole.prototype , HoleMixin , ValidateMixin , ObseerverMixin);
- mixinベースのプログラミングを行うよりも、まずはプリミティブや配列オブジェクトなどのシンプルなデータ型を試みることをお勧め
- 非常に厳密なインターフェイスを持った特化データ型を扱うのであれば、mixinもよい