致电与申请之间有什么区别?

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

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

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

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

答案

区别在于apply允许您将arguments作为数组调用函数; call需要显式列出参数。有用的助记为“用于对C OMMA 一个 rray 和C A”。

有关applycall的信息,请参见 MDN 的文档。

伪语法:

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. Scott Allen 在这件事上写得很好

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

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

所以:

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

要回答有关何时使用每个函数的部分,如果您不知道要传递的参数数量,或者它们已经存在于数组或类似数组的对象中(例如arguments对象可以转发自己的arguments ,请使用apply参数,否则使用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速度会更快。

这是一个很好的助记符。 一个人使用A rays,而一个人则使用一两个参数。当你用C所有你必须到C指望。2-15 参数的个数。

虽然这是一个老话题,但我只是想指出. 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” 中所述,window 是在 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.addValuesf引用相同的函数,但在调用时它们的行为也有所不同,因为每次调用中接收者的值都不同。出于这个原因,称这是指一种功能,当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]);

以下调用是等效的,因为fobj.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值不能为nullundefined 。如果将nullundefined提供为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 的工作方式如下:

  1. 绑定返回可以执行的函数的实例
  2. 第一个参数是 “ this
  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
*/

我想展示一个使用'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]

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

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

.call(scope, arg1, arg2, arg3)

和 apply()需要一个参数数组,例如:

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

以下是一些其他用法示例: http : //blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/