2014年6月17日
JavaScriptでbind()を使って部分適用する
本記事は、原著者の許諾のもとに翻訳・掲載しております。
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
も問題なく渡されます。
もし皆さんが数カ月前の私と同じなら、ショックで自分の書いたコードから似たような箇所を探してきてはクリーンアップしたくなることでしょう。その作業が終わったら、このことを友達にも教えてあげてください。
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
- Twitter: @yosuke_furukawa
- Github: yosuke-furukawa