来自:http://ejohn.org/apps/learn/#2
Function.prototype.bind = function(){
var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
return function(){
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
};
};
有谁能告诉我为什么第二次返回是必要的(在fn.apply之前)?
此外,任何人都可以解释为什么args.concat是必要的?为什么不把它重写为:
fn.apply(object, args)
而不是
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
答案 0 :(得分:7)
第二次返回是必要的,否则我们将失去绑定函数的任何返回值。
你可能已经知道这一点,但不要害怕提及。如果我们不将fn.apply
包装在另一个函数中,那么我们直接调用次优的函数fn
,因为bind
只应该设置执行上下文(应该是什么) this
引用函数内部,而不是调用它。
可以通过调用call
或apply
方法来调用Javascript方法。这是一个小例子:
function example() {
alert("useless example");
}
example.apply() // or example.call(), alerts "useless example";
Prototype的bind()中的外部函数应该像绑定函数周围的隐形包装一样工作。因此,传递给包装器的任何参数也应该传递给绑定函数,并且它必须返回绑定函数返回的任何值,这就是返回语句存在的原因。
在fn.apply中执行args.concat的原因是不同的,它不是可选的。 Prototype中的bind
允许您在绑定函数前添加参数。
args
表示我们在函数上调用bind
时传递的参数。 arguments
表示调用绑定函数时传递的参数。我们基本上在那里连接两个数组。
从上面的例子中可以看出:
var obj = { x: 'prop x' };
var boundExample = example.bind(obj, 12, 23); // args => 12, 23
boundExample(36, 49); // arguments => 36, 49
// arguments that our example() function receives => 12, 23, 36, 49
答案 1 :(得分:0)
旧帖但是更新的方法;)
Function.prototype.bind = function(){
var fn = this,
context = arguments[0],
args = Array.prototype.slice.call(arguments, 1);
return function(){
return fn.apply(context, args.concat([].slice.call(arguments)));
}
}
obj = {'abc':'x'};
var func = function() {
console.log(arguments);
alert(this.abc);
}
var x = func.bind(obj);
console.log(x(1,2,3));
这是一个很好的例子来解释。运行它并检查控制台日志。 然后修改代码以省略
[].slice.call(arguments)
您将看到执行x(1,2,3)的console.log不再显示参数。 这是因为arguments对象是所有函数中的局部变量。 这可能听起来有点令人困惑,但它的意思基本上是:
var x = func.bind(obj,1,2,3);
在内部返回此函数:
function() {
return fn.apply(obj, [1,2,3].concat([].slice.call(arguments)));
}
因此它更像是该功能的模板。
现在运行时如下:
x(4,5,6)
这将运行:
fn.apply(obj, [1,2,3].concat([].slice.call(arguments)))
使用特殊参数object = {0:4,1:5,2:6},可以使用[] .slice.call将其转换为数组 其中arguments是一个本地对象,它在函数调用期间自动被赋值。