使用之间有什么区别 call
和 apply
调用一个函数?
var func = function() {
alert('hello!');
};
func.apply();
VS func.call();
上述两种方法之间是否存在性能差异?何时最好使用 call
过度 apply
反之亦然?
使用之间有什么区别 call
和 apply
调用一个函数?
var func = function() {
alert('hello!');
};
func.apply();
VS func.call();
上述两种方法之间是否存在性能差异?何时最好使用 call
过度 apply
反之亦然?
不同之处在于 apply
让你调用函数 arguments
作为一个数组; call
要求显式列出参数。一个有用的助记符是 “一个 对于 一个rray和 C 对于 COMMA“。
伪语法:
theFunction.apply(valueForThis, arrayOfArgs)
theFunction.call(valueForThis, arg1, arg2, ...)
从ES6开始,还有可能 spread
用于的数组 call
功能,你可以看到兼容性 这里。
示例代码:
function theFunction(name, profession) {
console.log("My name is " + name + " and I am a " + profession +".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator
K.斯科特艾伦有 一篇很好的文章 就此事。
基本上,他们在处理函数参数方面有所不同。
apply()方法与call()相同,但apply()需要数组作为第二个参数。该数组表示目标方法的参数。“
所以:
// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
要回答关于何时使用每个功能的部分,请使用 apply
如果您不知道要传递的参数数量,或者它们是否已经在数组或类数组对象中(如 arguments
反对转发自己的论点。使用 call
否则,因为不需要将参数包装在数组中。
f.call(thisObject, a, b, c); // Fixed number of arguments
f.apply(thisObject, arguments); // Forward this function's arguments
var args = [];
while (...) {
args.push(some_value());
}
f.apply(thisObject, args); // Unknown number of arguments
当我没有传递任何论据时(比如你的例子),我更喜欢 call
因为我 调用 功能。 apply
会暗示你是 应用 (不存在的)参数的函数。
除非您使用,否则不应存在任何性能差异 apply
并将参数包装在一个数组中(例如 f.apply(thisObject, [a, b, c])
代替 f.call(thisObject, a, b, c)
)。我没有测试它,所以可能会有差异,但它将是非常浏览器特定的。这可能是 call
如果你还没有数组中的参数,那么会更快 apply
如果你这样做会更快。
这是一个很好的助记符。 一个pply使用 一个rrays和 一个lways需要一两个参数。当你使用 C所有你需要的 C数量参数的数量。
虽然这是一个古老的话题,但我只想指出.call比.apply略快。我无法确切地告诉你原因。
见jsPerf, http://jsperf.com/test-call-vs-apply/3
[UPDATE!
]
Douglas Crockford简要提到了两者之间的区别,这可能有助于解释性能差异...... http://youtu.be/ya4UHuXNygM?t=15m52s
Apply接受一组参数,而Call接受零个或多个单独的参数!啊哈!
.apply(this, [...])
.call(this, param1, param2, param3, param4...)
跟随摘录 关闭:Michael Bolin的权威指南。它可能看起来有点冗长,但它充满了很多洞察力。从“附录B.经常误解的JavaScript概念”:
this
指的是调用函数时调用表单的函数时 foo.bar.baz()
, 物体 foo.bar
被称为接收器。调用该函数时,它是用作值的接收器 this
:
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时的全局对象。这会导致一些令人惊讶的行为:
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
参考相同的函数,它们在被调用时表现不同,因为每次调用时接收器的值都不同。因此,在调用引用的函数时 this
,确保这一点很重要 this
调用时将具有正确的值。要清楚,如果 this
没有在函数体中引用,然后是行为 f(20)
和 obj.addValues(20)
会是一样的。
因为函数是JavaScript中的第一类对象,所以它们可以有自己的方法。所有功能都有方法 call()
和 apply()
这使得重新定义接收器(即,对象)成为可能 this
在调用函数时指的是)。方法签名如下:
/**
* @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()
如果未指定,则使用其自己的接收器的值来替换receiver参数,以下内容将不起作用:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
的价值 this
永远不可能 null
要么 undefined
当一个函数被调用。什么时候 null
要么 undefined
作为接收器提供 call()
要么 apply()
,全局对象用作接收器的值。因此,前面的代码具有添加名为的属性的相同的不良副作用 value
到全球对象。
将函数视为不知道分配给它的变量可能会有所帮助。这有助于强化这样一种观点,即在调用函数时,而不是在定义函数时,它的值将被约束。
提取物结束。
有时一个对象借用另一个对象的函数是有用的,这意味着借用对象只是执行lent函数,就像它自己一样。
一个小代码示例:
var friend = {
car: false,
lendCar: function ( canLend ){
this.car = canLend;
}
};
var me = {
car: false,
gotCar: function(){
return this.car === true;
}
};
console.log(me.gotCar()); // false
friend.lendCar.call(me, true);
console.log(me.gotCar()); // true
friend.lendCar.apply(me, [false]);
console.log(me.gotCar()); // false
这些方法对于为对象提供临时功能非常有用。
Call,Apply和Bind的另一个例子。 Call和Apply之间的区别很明显,但是 捆绑 像这样工作:
}
function Person(name) {
this.name = name;
}
Person.prototype.getName = function(a,b) {
return this.name + " " + a + " " + b;
}
var reader = new Person('John Smith');
reader.getName = function() {
// Apply and Call executes the function and returns value
// Also notice the different ways of extracting 'getName' prototype
var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
console.log("Apply: " + baseName);
var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy");
console.log("Call: " + baseName);
// Bind returns function which can be invoked
var baseName = Person.prototype.getName.bind(this, "is a", "boy");
console.log("Bind: " + baseName());
}
reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/