2011-12-18 49 views
3

这是_.bind的代码,取自Underscore library。我不明白的走空函数的业务,改变其原型等了解_.bind的代码

var ctor = function(){}; 

    _.bind = function bind(func, context) { 
    var bound, args; 
    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); 
    if (!_.isFunction(func)) throw new TypeError; 
    args = slice.call(arguments, 2); 
    return bound = function() { 
     if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); 
     ctor.prototype = func.prototype; 
     var self = new ctor; 
     var result = func.apply(self, args.concat(slice.call(arguments))); 
     if (Object(result) === result) return result; 
     return self; 
    }; 
    }; 
+1

我在这里没有看到真正的问题。 – 2011-12-18 16:09:49

回答

8

它基本上是有,这样,如果你打电话new bound(),你能够绑定参数为new电话。例如:

var func = function(a, b) { 
    this.a = a; 
    this.b = b; 
}; 

// context does not matter, use e.g. `null` 
var bound = _.bind(func, null, 1); 

new bound(2); // a = 1, b = 2 

我试着解释一下代码。

var ctor = function(){}; 

_.bind = function bind(func, context) { 
    var bound, args; 

    // use native .bind if available 
    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); 

    // abort if not called with a function 
    if (!_.isFunction(func)) throw new TypeError; 

    // you can also bind arguments, which come after the function and context (so .slice(2)) 
    args = slice.call(arguments, 2); 

    // return the bound function 
    return bound = function() { 

     // if you simply do bound(), then `this` is the global object. 
     // This means the original function should be called with the 
     // bound `this` value and arguments. Arguments you pass to the 
     // bound function are concatenated to the bound arguments. 
     if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); 

     // otherwise, you're calling like `new bound()`, because `this instanceof bound`. 
     // In that case, `this` should not be passed, but only the arguments. So, you 
     // create a function of which the prototype is the original function's prototype, 
     // and create an instance of it (to mimic `new func`). 
     ctor.prototype = func.prototype; 

     var self = new ctor; // won't execute anything since ctor's body is empty. 
          // Just creates an instance 

     // then, you call the original function with the `this` value of the instance, 
     // with bound arguments and new arguments concatenated. This way, the constructor 
     // (func) is executed on the instance. 
     var result = func.apply(self, args.concat(slice.call(arguments))); 

     // finally, return the result if it's an object (the specs say `new xxx` should 
     // return an object), otherwise return the instance (like you would with `new func`) 
     if (Object(result) === result) return result; 
     return self; 
    }; 
};