call 和 apply 和有什么不一样?

IT技术 javascript performance function dynamic
2021-01-17 01:52:43

使用Function.prototype.apply()Function.prototype.call()调用函数有什么区别

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

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

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

6个回答

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

请参阅 MDN 关于applycall的文档

伪语法:

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

@KunalSingh双方callapply采用两个参数。apply' and call` 函数的第一个参数必须是所有者对象,第二个参数将分别是数组或逗号分隔的参数。如果您传递nullundefined作为第一个参数,那么在非严格模式下,它们将被替换为全局对象,即window
2021-03-12 01:52:43
我经常忘记哪个需要一个数组,哪个需要你列出参数。我用来记住它的技术是如果与该方法开始的第一个字母一个那么它带有一个数组即 一个pply阵列
2021-03-28 01:52:43
@KevinSchroeder:在 javascript 中,[]称为数组{}称为对象
2021-04-02 01:52:43
要添加的一件事是 args 必须是数值数组 ([])。关联数组 ({}) 不起作用。
2021-04-07 01:52:43
@SAM 使用call而不是普通的函数调用只有在您需要更改函数调用this值时才有意义一个示例(将函数参数对象转换为数组):Array.prototype.slice.call(arguments)[].slice.call(arguments)如果您在数组中有参数,例如在调用具有(几乎)相同参数的另一个函数的函数中,apply是有意义的。建议funcname(arg1)如果可以满足您的需要,请使用普通函数调用,并保存调用在您真正需要它们的特殊场合申请
2021-04-07 01:52:43

K. Scott Allen 有一篇关于此事的好文章。

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

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

所以:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
apply() 和 call() 的第二个参数是可选的,不是必需的。
2021-03-13 01:52:43
@Ikrom,第一个参数不是必需的,call而是必需apply
2021-03-28 01:52:43
第一个参数也不是必需的。
2021-03-31 01:52:43

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

这是一个很好的助记符。 A ply使用A数组,而A总是使用一两个参数。当您使用Ç所有你必须ç指望。2-15参数的个数。

有用的助记符就在那里!我会将“一个或两个参数”更改为“最多两个参数”,因为不需要第一个或第二个参数apply我不确定为什么会调用applycall不带参数。看起来有人试图找出这里的原因stackoverflow.com/questions/15903782/...
2021-03-14 01:52:43

虽然这是一个老话题,但我只想指出 .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...)

1. 创建一个新数组意味着垃圾收集器需要在某个时候清理它。2. 使用解引用访问数组中的项比直接访问变量(参数)效率低。(我相信这就是 kmatheny 所说的“解析”的意思,这实际上是完全不同的东西。)但是我的论点都没有解释 jsperf。这一定与引擎对这两个函数的实现有关,例如,如果没有传递,它们可能无论如何都会创建一个空数组。
2021-03-17 01:52:43
@JoshMc 那将是非常特定于浏览器的。在 IE 11 中,我的 apply 速度是 call 的两倍。
2021-03-24 01:52:43
这取决于函数对参数/数组的处理方式,如果不需要处理数组,是否需要更少的时间?
2021-03-30 01:52:43
感谢您分享测试和视频
2021-04-04 01:52:43
有趣的是,即使没有数组,调用仍然要快得多。jsperf.com/applyvscallvsfn2
2021-04-08 01:52:43