使用Function.pr原型.apply()和Function.pr原型.call()调用函数有什么区别?

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

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

上述两种方法之间是否存在性能差异?何时最好使用呼叫转移应用,反之亦然?


当前回答

这是一个很好的助记符。应用使用数组,始终使用一个或两个参数。使用Call时,必须计算参数的数量。

其他回答

调用和应用都用于在执行函数时强制此值。唯一的区别是调用采用n+1个参数,其中1是this和“n”个参数。apply只接受两个参数,一个是this,另一个是argument数组。

我在apply-over-call中看到的优点是,我们可以轻松地将函数调用委托给其他函数,而无需付出太多努力;

function sayHello() {
  console.log(this, arguments);
}

function hello() {
  sayHello.apply(this, arguments);
}

var obj = {name: 'my name'}
hello.call(obj, 'some', 'arguments');

观察我们使用apply将hello委托给sayHello有多容易,但使用call很难做到这一点。

K.Scott Allen对这件事有很好的评论。

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

apply()方法与call()方法相同,只是apply(需要一个数组作为第二个参数。数组表示目标方法的参数。"

So:

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

以下摘自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()都是位于Function.prototype上的方法。因此,它们可以通过原型链在每个函数对象上使用。call()和apply()都可以执行具有指定值this的函数。

call()和apply()之间的主要区别是必须向其中传递参数的方式。在call()与apply(()中,您都将希望作为值的对象作为第一个参数传递为this。其他参数的不同之处如下:

使用call(),您必须正常输入参数(从第二个参数开始)使用apply(),必须传入参数数组。

例子:

让obj={val1:5,值2:10}常量总和=函数(val3,val4){返回this.val1+this.val2+val3+val4;}console.log(summary.apply(obj,[2,3]));//首先,我们在第一个参数中为其赋值//使用apply,我们必须传入一个数组console.log(summary.call(obj,2,3));//通过调用,我们可以单独传入每个参数

为什么我需要使用这些功能?

在javascript中,这个值有时很棘手。该值在执行函数时确定,而不是在定义函数时确定。如果我们的函数依赖于此绑定的权限,我们可以使用call()和apply()来强制执行此行为。例如:

var name='unwantedGlobalName';常量对象={name:“Willem”,sayName(){console.log(this.name);}}let copiedMethod=obj.sayName;//我们将函数存储在copiedmethod变量中copiedMethod();//现在是窗口,unwantedGlobalName将被记录copiedMethod.call(obj);//我们强制这是obj,Willem被记录

我想展示一个示例,其中使用了“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*