为了这个问题,假设我希望能够在Javascript中创建一个函数,将一个数组的所有元素追加到另一个数组。实现这一目标的一种方法是,如果您有权访问目标数组,那就说:
var destination = [1,2,3];
var source = [4,5];
Array.prototype.push.apply(destination, source);
console.log(destination); // [1,2,3,4,5]
现在,由于Array.prototype.push.apply非常丑陋,我想将它别名为更好的东西,例如:
var pushAll = Array.prototype.push.apply;
我应该能够使用两个参数调用,即上下文(destination)和一个参数数组(source)。但是,当我尝试使用别名时,会发生这种情况:
pushAll(destination, [6,7]);
TypeError: Function.prototype.apply was called on [object global], which
is a object and not a function
很明显apply
函数没有绑定到push
,这导致我尝试这个:
var pushAll = Function.prototype.apply.bind(Array.prototype.push);
pushAll(destination, [6,7]);
console.log(destination); // [1,2,3,4,5,6,7,8]
这显然很好用。我的问题是,为什么我必须绑定push方法才能应用?不应该绑定Array.prototype.push.apply吗?为什么以不同的名称调用它会导致在未绑定的上下文中调用它?
答案 0 :(得分:5)
为什么我必须绑定push方法才能应用?
反过来说:你必须将apply方法绑定到Array push函数 - 你也可以将它绑定到其他函数!否则apply
不知道应用参数的方法。
Function.prototype.apply.bind(Array.prototype.push);
确实在bind
函数上调用apply
函数,push
作为参数,参数 on 然后绑定apply
。调用后,生成的函数pushAll
将在apply
函数上调用push
,并将其参数(数组和参数数组)传递给它。
不应该绑定Array.prototype.push.apply吗?
不。 JavaScript被设计为在函数调用时绑定上下文,当它被称为属性时尚未绑定 - 对属性访问没有隐式绑定。否则Array.prototype.push
已经绑定到Array.prototype
,然后你可以调用任何函数方法,比如bind / apply,并尝试在不同的上下文中使用它。
为什么以不同的名称调用它会导致在未绑定的上下文中调用它?
这不是一个不同的名字,而是不同的风格。 (未绑定)函数确实将this
值设置为对象,当它们被称为作为方法时,即当对被调用函数的引用是属性访问时:{{1 }}
这允许很大的灵活性,你可以从一个对象“借用”函数并在其他对象上调用它们,仍然是相同的(未绑定)函数。在函数对象不是第一类对象的语言中,这是不可能的。
如果函数(即使它们是方法)被称为普通函数(destination.push()
),它们的pushAll()
值将为this
(除非在草率模式下)。详细了解MDN的this
keyword。