我想知道是否有人知道为什么 call
比apply
快得多?在chrome中,它大约快4倍,在firefox中大约是30倍,我甚至可以制作一个自定义原型apply2
,它(在大多数情况下)运行速度是apply
的2倍(从角度来看的想法:
Function.prototype.apply2 = function( self, arguments ){
switch( arguments.length ){
case 1: this.call( self, arguments[0] ); break;
case 2: this.call( self, arguments[0], arguments[1] ); break;
case 3: this.call( self, arguments[0], arguments[1], arguments[2] ); break;
case 4: this.call( self, arguments[0], arguments[1], arguments[2], arguments[3] ); break;
case 5: this.call( self, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4] ); break;
case 6: this.call( self, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5] ); break;
case 7: this.call( self, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6] ); break;
case 8: this.call( self, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7] ); break;
case 9: this.call( self, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8] ); break;
case 10: this.call( self, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9] ); break;
default: this.apply( self, arguments ); break;
}
};
所以有人知道为什么吗?
答案 0 :(得分:15)
引用ECMAScript Language Specification 5.1 Edition (June 2011):
当使用参数thisArg和argArray在对象func上调用apply
方法时,将执行以下步骤:
如果IsCallable(func)
为false
,则抛出TypeError
例外。
如果argArray
是null
或undefined
,那么
return
调用[[Call]]
func
内部方法的结果,提供thisArg
作为this
值和空参数列表。
Type(argArray)
不是Object
,则抛出TypeError
例外。len
成为调用[[Get]]
内部方法的结果
带有参数argArray
的{{1}}。"length"
成为n
。ToUint32(len)
为空argList
。List
为0。index
index < n
成为indexName
。ToString(index)
成为调用nextArg
内部方法的结果
以[[Get]]
为参数的argArray
。indexName
添加为nextArg
的最后一个元素。argList
设为index
。index + 1
[[Call]]
内部方法的结果,
提供func
作为thisArg
值,this
作为列表
参数。当使用参数thisArg和可选参数arg1,arg2等在对象func上调用argList
方法时,将执行以下步骤:
call
为IsCallable(func)
,则抛出false
例外。TypeError
为空argList
。List
开头的正确顺序将每个参数作为最后一个附加
arg1
argList
[[Call]]
内部方法的结果,
提供func
作为thisArg
值,this
作为列表
参数。正如我们所看到的,指定argList
的格式显然更重,并且由于需要更改参数的格式以及最终需要它们的方式,因此需要执行更多操作。
apply
中有许多检查由于输入格式的不同而在apply
中不是必需的。
另一个关键点是参数循环的方式(call
中的步骤4-12,隐含在apply
的第3步中):循环的整个设置在{ {1}}无论实际存在多少个参数,call
所有这些只在需要时才会完成
此外,值得注意的是,apply
中实施步骤3的方式未被指定,这有助于解释不同浏览器行为的巨大差异。
所以简要回顾一下:call
比call
快,因为输入参数已经根据内部方法的需要进行了格式化。
请务必阅读以下评论以供进一步讨论。