Javascript call 和 apply 和有什么不一样?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1986896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 22:15:15  来源:igfitidea点击:

What is the difference between call and apply?

javascriptperformancefunctiondynamic

提问by John Duff

What is the difference between using calland applyto invoke a function?

使用callapply调用函数有什么区别?

var func = function() {
  alert('hello!');
};

func.apply();vs func.call();

func.apply();对比 func.call();

Are there performance differences between the two aforementioned methods? When is it best to use callover applyand vice versa?

上述两种方法之间是否存在性能差异?什么时候最好使用callover apply,反之亦然?

回答by flatline

The difference is that applylets you invoke the function with argumentsas an array; callrequires the parameters be listed explicitly. A useful mnemonic is "Afor array and Cfor comma."

不同之处在于apply,您可以将函数arguments作为数组调用;call需要明确列出参数。有用的助记是用于一个rray和çÇOMMA”。

See MDN's documentation on applyand call.

请参阅 MDN 有关applycall的文档。

Pseudo syntax:

伪语法:

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

theFunction.call(valueForThis, arg1, arg2, ...)

There is also, as of ES6, the possibility to spreadthe array for use with the callfunction, you can see the compatibilities here.

从 ES6 开始,还可以spread将数组与call函数一起使用,您可以在此处查看兼容性。

Sample code:

示例代码:

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

回答by notnoop

K. Scott Allen has a nice writeupon the matter.

K. Scott Allen 有一篇关于这个问题的好文章。

Basically, they differ on how they handle function arguments.

基本上,它们在处理函数参数的方式上有所不同。

The apply() method is identical to call(), except apply() requires an array as the second parameter. The array represents the arguments for the target method."

apply() 方法与 call() 相同,除了 apply() 需要一个数组作为第二个参数。该数组表示目标方法的参数。”

So:

所以:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);

回答by Matthew Crumley

To answer the part about when to use each function, use applyif you don't know the number of arguments you will be passing, or if they are already in an array or array-like object (like the argumentsobject to forward your own arguments. Use callotherwise, since there's no need to wrap the arguments in an array.

要回答有关何时使用每个函数的部分,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

When I'm not passing any arguments (like your example), I prefer callsince I'm callingthe function. applywould imply you are applyingthe function to the (non-existent) arguments.

当我不传递任何参数(如您的示例)时,我更喜欢,call因为我正在调用该函数。apply意味着你正在申请的功能的(不存在)的参数。

There shouldn't be any performance differences, except maybe if you use applyand wrap the arguments in an array (e.g. f.apply(thisObject, [a, b, c])instead of f.call(thisObject, a, b, c)). I haven't tested it, so there could be differences, but it would be very browser specific. It's likely that callis faster if you don't already have the arguments in an array and applyis faster if you do.

不应该有任何性能差异,除非您使用apply并将参数包装在数组中(例如,f.apply(thisObject, [a, b, c])而不是f.call(thisObject, a, b, c))。我没有测试过它,所以可能会有差异,但它会非常特定于浏览器。call如果您还没有数组中的参数,这可能会更快,如果您这样做,速度可能会更快apply

回答by Joe

Here's a good mnemonic. Apply uses Arrays and Always takes one or two Arguments. When you use Call you have to Count the number of arguments.

这是一个很好的助记符。 一个pply使用一个rrays和一个lways带一个或两个参数。当您使用Ç所有你必须ç指望。2-15参数的个数。

回答by kmatheny

While this is an old topic, I just wanted to point out that .call is slightly faster than .apply. I can't tell you exactly why.

虽然这是一个老话题,但我只想指出 .call 比 .apply 稍快。我不能确切地告诉你为什么。

See jsPerf, http://jsperf.com/test-call-vs-apply/3

参见 jsPerf,http://jsperf.com/test-call-vs-apply/3



[UPDATE!]

[ UPDATE!]

Douglas Crockford mentions briefly the difference between the two, which may help explain the performance difference... http://youtu.be/ya4UHuXNygM?t=15m52s

Douglas Crockford 简要提到了两者之间的区别,这可能有助于解释性能差异... http://youtu.be/ya4UHuXNygM?t=15m52s

Apply takes an array of arguments, while Call takes zero or more individual parameters! Ah hah!

Apply 接受一组参数,而 Call 接受零个或多个单个参数!啊哈!

.apply(this, [...])

.apply(this, [...])

.call(this, param1, param2, param3, param4...)

.call(this, param1, param2, param3, param4...)

回答by Dominykas Mostauskis

Follows an extract from Closure: The Definitive Guide by Michael Bolin. It might look a bit lengthy, but it's saturated with a lot of insight. From "Appendix B. Frequently Misunderstood JavaScript Concepts":

遵循Closure: The Definitive Guide by Michael Bolin的摘录。它可能看起来有点冗长,但它充满了很多洞察力。来自“附录 B. 经常被误解的 JavaScript 概念”:



What thisRefers to When a Function is Called

this当函数被调用时指的是什么

When calling a function of the form foo.bar.baz(), the object foo.baris referred to as the receiver. When the function is called, it is the receiver that is used as the value for 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);

If there is no explicit receiver when a function is called, then the global object becomes the receiver. As explained in "goog.global" on page 47, window is the global object when JavaScript is executed in a web browser. This leads to some surprising behavior:

如果在调用函数时没有显式接收器,则全局对象将成为接收器。如第 47 页的“goog.global”中所述,当 JavaScript 在 Web 浏览器中执行时,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

Even though obj.addValuesand frefer to the same function, they behave differently when called because the value of the receiver is different in each call. For this reason, when calling a function that refers to this, it is important to ensure that thiswill have the correct value when it is called. To be clear, if thiswere not referenced in the function body, then the behavior of f(20)and obj.addValues(20)would be the same.

即使obj.addValuesf指的是同一个函数,它们在调用时的行为也不同,因为每次调用中接收者的值都不同。因此,在调用引用 的函数时,this重要的是要确保this在调用时具有正确的值。需要明确的是,如果this在函数体中并没有提及,那么行为f(20)obj.addValues(20)将是相同的。

Because functions are first-class objects in JavaScript, they can have their own methods. All functions have the methods call()and apply()which make it possible to redefine the receiver (i.e., the object that thisrefers to) when calling the function. The method signatures are as follows:

因为函数是 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;

Note that the only difference between call()and apply()is that call()receives the function parameters as individual arguments, whereas apply()receives them as a single array:

请注意,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]);

The following calls are equivalent, as fand obj.addValuesrefer to the same function:

下面的调用是等价的,f并且obj.addValues指的是相同的功能:

obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);

However, since neither call()nor apply()uses the value of its own receiver to substitute for the receiver argument when it is unspecified, the following will not work:

但是,由于既没有call()也没有apply()使用其自己的接收器的值来替换未指定的接收器参数,因此以下将不起作用:

// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);

The value of thiscan never be nullor undefinedwhen a function is called. When nullor undefinedis supplied as the receiver to call()or apply(), the global object is used as the value for receiver instead. Therefore, the previous code has the same undesirable side effect of adding a property named valueto the global object.

的值this永远不能是nullundefined函数被调用时。当nullorundefined作为接收者提供给call()or 时apply(),全局对象被用作接收者的值。因此,前面的代码具有相同的不良副作用,即向value全局对象添加命名的属性。

It may be helpful to think of a function as having no knowledge of the variable to which it is assigned. This helps reinforce the idea that the value of this will be bound when the function is called rather than when it is defined.

将函数视为不知道分配给它的变量可能会有所帮助。这有助于强化 this 的值将在调用函数时而不是在定义时绑定的想法。



End of extract.

提取结束。

回答by tHymans3

It is useful at times for one object to borrow the function of another object, meaning that the borrowing object simply executes the lent function as if it were its own.

有时一个对象借用另一个对象的函数很有用,这意味着借用对象只是像执行自己的函数一样执行借出的函数。

A small code example:

一个小代码示例:

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

These methods are very useful for giving objects temporary functionality.

这些方法对于为对象提供临时功能非常有用。

回答by Mahesh

Another example with Call, Apply and Bind. The difference between Call and Apply is evident, but Bindworks like this:

调用、应用和绑定的另一个示例。Call 和 Apply 之间的区别很明显,但是Bind 的工作方式是这样的:

  1. Bind returns an instance of a function that can be executed
  2. First Parameter is 'this'
  3. Second parameter is a Comma separatedlist of arguments (like Call)
  1. 绑定返回一个可以执行的函数的实例
  2. 第一个参数是“这个
  3. 第二个参数是逗号分隔的参数列表(如Call

}

}

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
*/

回答by Mahesh

I'd like to show an example, where the 'valueForThis' argument is used:

我想展示一个例子,其中使用了“valueForThis”参数:

Array.prototype.push = function(element) {
   /*
   Native code*, that uses 'this'       
   this.put(element);
   */
}
var array = [];
array.push(1);
array.push.apply(array,[2,3]);
Array.prototype.push.apply(array,[4,5]);
array.push.call(array,6,7);
Array.prototype.push.call(array,8,9);
//[1, 2, 3, 4, 5, 6, 7, 8, 9] 

**details: http://es5.github.io/#x15.4.4.7*

**详情:http: //es5.github.io/#x15.4.4.7*

回答by Mark Karwowski

Call() takes comma-separated arguments, ex:

Call() 采用逗号分隔的参数,例如:

.call(scope, arg1, arg2, arg3)

.call(scope, arg1, arg2, arg3)

and apply() takes an array of arguments, ex:

和 apply() 接受一个参数数组,例如:

.apply(scope, [arg1, arg2, arg3])

.apply(scope, [arg1, arg2, arg3])

here are few more usage examples: http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/

这里还有一些用法示例:http: //blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/