我在jsGarden中遇到了这个代码,我无法想象将call
和apply
链接在一起的含义。两者都将使用给定的上下文对象执行该函数,为什么它可以被链接?
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
// Create an unbound version of "method"
// It takes the parameters: this, arg1, arg2...argN
Foo.method = function() {
// Result: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};
它正在通过call
打电话给apply
;也就是说,它使用call
来调用一个函数(“方法”),并且它使用apply
进行调用,因为它以(几乎)数组的形式获得了参数。
所以把它分开:
Function.call
这是对所有Function实例上可用的call()
函数的引用,继承自Function原型。
Function.call.apply
通过引用call
函数,这是apply
的参考。因为apply
是通过call
对象引用的,所以当调用apply
时,this
值将是对call
函数的引用。
Function.call.apply(Foo.prototype.method, arguments);
所以我们通过call
调用apply
函数,并将Foo.prototype.method
作为this
值传递,并将“Foo.mmethod”作为参数传递。
我认为它与此基本相同:
Foo.method = function() {
var obj = arguments[0], args = [].slice.call(arguments, 1);
Foo.prototype.method.apply(obj, args);
}
但我必须尝试确保。编辑是的,似乎是它。因此,当所需的apply()
值是保存参数的数组的第一个元素时,我可以总结一下这个技巧的点是一种调用this
的方法。换句话说,通常当您调用apply()
时,您已获得所需的this
对象引用,并且您已获得参数(在数组中)。但是,由于这个想法是你传递了所需的this
作为参数,所以需要将它分离出来以便调用apply
。就个人而言,我会像在我的“翻译”中那样做,因为它对我来说有点不那么令人费解(但对我而言),但我想人们可以习惯它。根据我的经验,这不是常见的情况。
我认为代码应该是这样的:
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
Foo.method = function() {
//Notice this line:
Function.apply.call(Foo.prototype.method, this, arguments);
};
然后
Foo.method(1,2,3) => function Foo() {} 1 2 3
其他例子:
Function.apply.call(Array,this,[1,2]) => [1, 2]
Function.call.apply(Array,this,[1,2]) => [window]
Function.call.call(Array,this,[1,2]) => [[1, 2]]
// lets take call,
var callfn = Function.prototype.call;
// an ordinary function from elsewhere
var method = Foo.prototype.method;
// and apply the arguments object on it:
callfn.apply(method, arguments);
因此,第一个arguments
项目将是this
的method
值,随后将填充单个参数。
结果是在method
构造函数上的静态函数Foo
,它将Foo
实例(或类似的东西)作为第一个参数并在其上应用原型method
。一个可能的用例是定义一个Object.hasOwnProperty
函数,它通常只能作为Object.prototype.hasOwnProperty
使用。
最终,如果你需要将它应用于a)不继承它或b)覆盖它的对象,它会使method
调用一个“原型”和一个“调用”更短。
Person.prototype.fullname = function(joiner, options) {
options = options || { order: "western" };
var first = options.order === "western" ? this.first : this.last;
var last = options.order === "western" ? this.last : this.first;
return first + (joiner || " ") + last;
};
// Create an unbound version of "fullname", usable on any object with 'first'
// and 'last' properties passed as the first argument. This wrapper will
// not need to change if fullname changes in number or order of arguments.
Person.fullname = function() {
// Result: Person.prototype.fullname.call(this, joiner, ..., argN);
return Function.call.apply(Person.prototype.fullname, arguments);
};
来自Javascript Garden的代码。
请注意它说明了
Function.call.apply(Person.prototype.fullname, arguments);will become this:
Person.prototype.fullname.call(this, joiner, ..., argN);
这意味着首先执行apply()函数,然后执行call()函数。
模式:最合适的call() / apply()
将首先被执行
apply()
将首先被执行apply()
的上下文成为call()
函数的调用者,所以现在
Person.prototype的,fullname.call()apply()
can只接受一个参数数组,所以apply()
为arguments
函数提供call()
,所以现在
Person.prototype的,fullname.call(参数)来自@foxiris的例子
第一号:
Function.apply.call(Array,this,[1,2])
call()
将首先被执行call()
的背景成为apply()
的来电者,所以现在Array.apply()
call()
到this
,所以现在[1, 2]
,它将输出apply()
第二个:
Function.call.apply(Array,this,[1,2])
Array.apply(this, [1, 2]);
将首先被执行[1, 2]
的背景成为apply()
的来电者,所以nowapply()
call()
只能采用一个单一的数组参数,所以它只能提供Array.call()
到apply()
,所以现在this
,输出是call()
。第三个:
Function.call.call(Array,this,[1,2])
Array.call(this);
将首先被执行[]
(最右边的一个)的背景成为call()
的调用者(右边第二个),所以现在call()
call()
可以采取多个参数,所以它可以提供Array.call()
和call()
到另一个this
,所以现在[1, 2]
,输出是call()
。