call 比 apply 快的多,下面代码运行结果
function work(a, b, c) {}
var a = [1, 2, 3];
console.time('call');
for (var i = 0; i < 1000000; i++) {
work.call(this, 1, 2, 3);
}
console.timeEnd('call');
for (var j = 0; j < 5; j++) {
console.time('apply');
for (var i = 0; i < 1000000; i++) {
work.apply(this, a);
}
console.timeEnd('apply');
console.time('call');
for (var i = 0; i < 1000000; i++) {
work.call(this, 1, 2, 3);
}
console.timeEnd('call');
}
google chrome Version 62 结果显示如下:
VM125:16 call: 5.592041015625ms
VM125:16 apply: 17.97705078125ms
VM125:22 call: 3.798828125ms
VM125:16 apply: 18.8818359375ms
VM125:22 call: 2.841064453125ms
VM125:16 apply: 15.654052734375ms
VM125:22 call: 2.47900390625ms
VM125:16 apply: 15.90087890625ms
VM125:22 call: 2.311767578125ms
VM125:16 apply: 15.912109375ms
VM125:22 call: 2.385986328125ms
原因在与.apply在运行前要对作为参数的数组进行一系列检验和深拷贝,.call则没有这些步骤。具体可以参考ECMA .
深拷贝是指将.apply()的第二个参数(数组)深拷贝到JS引擎内部创建的argList里。
.call和.apply运行的时候都会创建一个参数序列(Argument Lists)叫做argList。.call只需要将参数逐一放到argList里面。而.apply的参数是数组,需要获得其中每一个元素的值再放到argList里面。
大致步骤是:
-
Let argList be an empty List.
-
Let index be 0.
-
Repeat while index < n
-
Let indexName be ToString(index).
-
Let nextArg be the result of calling the [[Get]] internal method of argArray with indexName as the argument. Append nextArg as the last element of argList.
-
Set index to index + 1.