underscore.jsのbindとカリー化

underscore.jsのbindについてのメモです。

underscore.jsのbind

第1引数の関数を実行する「関数」を返す
第1引数の関数内の「this」は第2引数の値が使われる
コメントにある通り、第3引数以降を渡すとカリー化ができます。


定義は以下の通りです。

  // Create a function bound to a given object (assigning `this`, and arguments,
  // optionally). Binding with arguments is also known as `curry`.
  _.bind = function(func, obj) {
    var args = slice.call(arguments, 2);
    return function() {
      return func.apply(obj || {}, args.concat(slice.call(arguments)));
    };
  };


公式ドキュメントに記載されている使用例です。

var func = function(greeting){ return greeting + ': ' + this.name };
func = _.bind(func, {name : 'moe'}, 'hi');
func();
=> 'hi: moe'


上記使用例の場合どうなるかをコメントで示してみます

  _.bind = function(func, obj) {
    // funcは function(greeting){ return greeting + ': ' + this.name };
    // objは{name: 'moe'}
    var args = slice.call(arguments, 2); // ['hi']
    return function() {
      // bind時に渡された引数'hi'と、実行時に渡された引数をconcatしたものを引数として、funcを呼び出す関数を返す
      return func.apply(obj || {}, args.concat(slice.call(arguments)));
    };
  };


以下は、JavaScriptパターンで紹介されているカリー化の例です。

function schonfinkelize(fn) {
 var slice = Array.prototype.slice,
      stored_args = slice.call(arguments, 1);
 return function(){
      var new_args = slice.call(arguments),
          args = stored_args.concat(new_args);
       return fn.apply(null, args);
};
}

function add(a, b, c, d, e){
	  return a + b + c + d + e
}

schonfinkelize(add, 1, 2, 3)(5, 5) 
// 16


underscore.jsのbindを使うと以下のように書けます

_.bind(add, null, 1, 2, 3)(5, 5)
// 16


ちなみにカリー化をpythonでやるには、functoolsのpartialが使えます。

import functools

def add(a, b, c, d, e):
    return a + b + c + d + e

functools.partial(add, 1, 2, 3)(5, 5)
# => 16


rubyではproc#curryメソッドが1.9から使えます。

add = lambda { |a,b,c,d,e| a+b+c+d+e }
add.curry[1,2,3].call(5,5)
# => 16

JavaScriptパターン ―優れたアプリケーションのための作法

JavaScriptパターン ―優れたアプリケーションのための作法