Original article: Partial Application in JavaScript using bind() by Pascal Hartig
JavaScriptの中にはコードをもっとシンプルで見やすくできるパターンがあるのに、あまり使われていないものがあります。皆さんもFunction.prototype.bindはご存じでしょう。頻繁に使われていたvar that = this
やvar self = this
の代わりになる関数です。よくあるのが以下のような例です。
this.setup = function () { this.on('event', this.handleEvent.bind(this)); };
第1引数がbind
(束縛)され、返される関数内でthis
として働きます。あまり知られていませんがbind
は複数の仮引数を取ることができ、bind
された関数が呼び出されるとbind
される後続のすべての仮引数は、その仮引数リストの前に付加されます。
つまり以下のように、関数を部分適用することができるのです。
var add = function (a, b) { return a + b; }; var add2 = add.bind(null, 2); add2(10) === 12;
すごいでしょう。冒頭に例として挙げたイベント処理コードを拡張する場合など、この利点がよく分かります。他にもイベント処理の一般的なパターンとしては、ハンドラを呼び出す時にコンテンツを指定するというのがあります。
this.setup = function () { this.on('tweet', function (e, data) { this.handleStreamEvent('tweet', e, data); }.bind(this)); this.on('retweet', function (e, data) { this.handleStreamEvent('retweet', e, data); }.bind(this)); };
仮にtweet
とretweet
のイベントハンドラが似かよった論理構造の場合、このようにコードを書くのもいいでしょう。ただし欠点は一目瞭然で、ボイラープレートコード(似ているのに省略できないお決まりのコード断片)だらけです。両方に無名関数を用意しなければなりませんし、それぞれ内部でイベントハンドラを呼び出して引数を受け渡し、関数をbind
してthis
コンテキストをきちんと設定しないといけません。
もう少しシンプルにできないものでしょうか? もちろんできますよ。
this.setup = function () { this.on('tweet', this.handleStreamEvent.bind(this, 'tweet')); this.on('retweet', this.handleStreamEvent.bind(this, 'retweet')); };
これならスッキリしますね。無名関数内で関数を呼び出す代わりに部分適用された関数を2つ用意し、thisコンテキストとそれぞれ異なる第1仮引数を両方に指定しました。もちろんe
やdata
も問題なく渡されます。
もし皆さんが数カ月前の私と同じなら、ショックで自分の書いたコードから似たような箇所を探してきてはクリーンアップしたくなることでしょう。その作業が終わったら、このことを友達にも教えてあげてください。