使用Function.pr原型.apply()和Function.pr原型.call()调用函数有什么区别?
var func = function() {
alert('hello!');
};
函数.apply();vs func.call();
上述两种方法之间是否存在性能差异?何时最好使用呼叫转移应用,反之亦然?
使用Function.pr原型.apply()和Function.pr原型.call()调用函数有什么区别?
var func = function() {
alert('hello!');
};
函数.apply();vs func.call();
上述两种方法之间是否存在性能差异?何时最好使用呼叫转移应用,反之亦然?
当前回答
这是一个很好的助记符。应用使用数组,始终使用一个或两个参数。使用Call时,必须计算参数的数量。
其他回答
虽然这是一个老话题,但我只是想指出,.call比.apply稍快。我不能告诉你确切的原因。
参见jsPerf,http://jsperf.com/test-call-vs-apply/3
[更新!]
Douglas Crockford简要提到了两者之间的差异,这可能有助于解释性能差异。。。http://youtu.be/ya4UHuXNygM?t=15m52s
Apply接受一个参数数组,而Call接受零个或多个单独的参数!啊哈!
.apply(此,[…])
.调用(this,param1,param2,param3,param4…)
我们可以区分调用和应用方法,如下所示
CALL:单独提供参数的函数。若您知道要传递的参数或并没有要传递的变量,则可以使用call。
APPLY:调用以数组形式提供参数的函数。如果不知道要传递给函数的参数有多少,可以使用apply。
使用applyovercall有一个优点,我们不需要更改参数的数量,只需要更改传递的数组即可。
性能上没有太大差异。但我们可以说,调用比应用更快,因为数组需要在apply方法中求值。
以下摘自Michael Bolin的《结束:最终指南》。它可能看起来有点冗长,但它充满了很多洞察力。摘自“附录B.经常误解的JavaScript概念”:
调用函数时所指的内容
当调用foo.bar.baz()形式的函数时,对象foo.bar被称为接收器。当函数被调用时,接收器被用作此函数的值:
var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
for (var i = 0; i < arguments.length; i++) {
this.value += arguments[i];
}
return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);
如果在调用函数时没有显式接收器,则全局对象将成为接收器。如第47页“goog.global”中所述,当在web浏览器中执行JavaScript时,window是全局对象。这导致了一些令人惊讶的行为:
var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN
尽管obj.addValues和f引用同一个函数,但它们在调用时的行为不同,因为每次调用中接收方的值都不同。因此,在调用引用此的函数时,务必确保在调用此函数时具有正确的值。要清楚的是,如果函数体中没有引用这一点,那么f(20)和obj.addValues(20)的行为将是相同的。
因为函数是JavaScript中的一流对象,所以它们可以有自己的方法。所有函数都有方法call()和apply(),这使得在调用函数时可以重新定义接收器(即它所指的对象)。方法签名如下:
/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;
请注意,call()和apply()之间的唯一区别是call()将函数参数作为单个参数接收,而apply(()将它们作为单个数组接收:
// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);
以下调用是等效的,因为f和obj.addValues引用同一个函数:
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
但是,由于call()和apply()在未指定接收方参数时都不使用自身接收方的值来替换接收方参数,因此以下操作将不起作用:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
调用函数时,this的值不能为null或未定义。当向call()或apply()提供null或undefined作为接收方时,将使用全局对象作为接收方的值。因此,前面的代码具有相同的不良副作用,即向全局对象添加一个名为value的属性。
将函数视为不知道其所分配的变量可能会有所帮助。这有助于强化这样一种观念,即当调用函数时,而不是定义函数时,它的值将被绑定。
提取结束。
不同之处在于,call()分别接受函数参数,而apply()接受数组中的函数参数。
call()方法调用具有给定this值和第二个参数(用逗号分隔的参数)的函数。
object.someMethod.call( someObject, arguments )
apply()方法与调用相同,只是它使用的第二个参数是一个参数数组。
object.someMethod.apply( someObject, arrayOfarguments )
var汽车={name:“雷诺”,国家:“法国”,showBuyer:函数(firstName,lastName){console.log(`${firstName}${lastName}刚刚从${this.country}购买了${this.name});}}const firstName=“Bryan”;const lastName=“Smith”;car.showBuyer(firstName,lastName);//布莱恩刚从法国买了一辆雷诺constobj={name:“玛莎拉蒂”,国家:“意大利”};car.showBuyer.call(obj,firstName,lastName);//布莱恩·史密斯刚从意大利买了一辆玛莎拉蒂car.showBuyer.apply(obj,[firstName,lastName]);//布莱恩·史密斯刚从意大利买了一辆玛莎拉蒂