アロー関数
ES6のアロー関数を使うと、無名関数を短く書くことができます。
無名関数とアロー関数を例を使って比較してみます。
無名関数の例
var getLength = function(s){ return s.length }
アロー関数の例
上の無名関数を次のように書けます
var getLength = s => s.length
- functionと書く必要がない
- 本文が1行の場合はreturnを書く必要がない
詳しい構文はMDNを読んでください。
C#のラムダ式と大体一緒です。
何が嬉しい?
対象の配列から干支か星座だけを取り出す関数を例にします。
// 干支、星座の定義
const eto = ['ne', 'ushi']
const constellations = ['aries', 'taurus']
// 辞書に含まれる名前だけを取り出す関数
function contains(dictionary, word){
return dictionary.indexOf(word) !== -1
}
// 干支だけ取りだすには・・・
['ne', 'aries'].filter(function(word){
return contains(eto, word);
})
上の干支を取り出す処理は、Underscore.jsのpartialを使って、事前にcontains関数の第一引数をバインドすることで、短く簡潔に書けます。
const isEto = _.partial(contains, eto);
['ne', 'aries'].filter(isEto)
アロー関数を使うと、Underscoreを使わなくても
['ne', 'aries'].filter(word => contains(eto, word))
短く書くことができます。
部分適用のつらさ
部分適用のメリット
もとの処理では、filterで使う無名関数外で定義した変数eto
を参照しています。
部分適用を使うと、eto
への参照と、干支を取り出す処理を分離できます。
干支を取り出す処理は、修正する際に考えることが減るため、より安全に修正できます。
また、部分適用を使うことで、引数の多い複雑な関数をラップして、使いやすい引数の短い関数を提供することができます。
_.partialでの部分適用のデメリット
_.partialを使って部分適用を行った場合、デバッグ時のコールスタックにpartialの呼び出しが挟まります。
コールスタックをたどって、呼び出し元を探すのが大変になります。
これは部分適用をライブラリとして実現しているため、回避不能です。
Function.prototype.bindでの部分適用のデメリット
JavaScriptが言語レベルでサポートしている部分適用にFunction.prototype.bindがあります。
これを使うと、コールスタックには関数呼び出ししか乗りません。
デバッグが大変になることを回避できます。
たとえば
const isEto = contains.bind(null, eto);
['ne', 'aries'].filter(isEto)
しかし、第一引数のnullが嫌な感じです。
第一引数なのが嫌です。もっとも重要な位置に、意味のない値を書くのが嫌です。
しかし、第一引数は関数内から参照するthisを指定する時には必要です。
thisは他の引数よりは重要な値ですので、第一引数にいるのは妥当に思えます。
Function.prototype.bindを使う場合、nullをなくす方法はありません。
部分適用が適用されるタイミング
部分適用自体の注意点です。
値が適用されるタイミングは、関数の実行時ではありません。
const x = 0
const logX = console.log.bind(console, x)
x = 1
logX() // 0
部分適用では、bindを実行した時の値がバインドされます。
クロージャのように、関数実行時の値にはなりません。
たとえば、次の例では...
const count = 0;
$('#count_button').on('click', function(){ count++ })
$('#inspect_button').on('click' console.log.bind(console, count))
いつ#inspect_button
ボタンを押しても0
を表示します。
これは、予想していない動作かもしれません。
まとめ
部分適用には
- _.partialではコールスタックが汚れる
- Function.prototype.bindでは
null
の記述が気にくわない - 変数ではなく値が適用される(ことが予想外になることがある)
というデメリットがあります。
単に書く量を減らすために部分適用を使うことはおすすめできません。
部分適用せずにアロー関数を使う
['ne', 'aries'].filter(word => contains(eto, word))
アロー関数は素敵です。無名関数に比べて悪い点はありません。
かつ今までより短くかけます。
アロー関数のつらさ
IE11では動きません。
IE11は滅ぼしましょう!