为什么打电话比申请快得多?

Mar*_*ahn 20 javascript

我想知道是否有人知道为什么 call这么快apply?在chrome中,它大约快了4倍,在firefox中大约是30倍,我甚至可以制作一个自定义原型,apply2它(在大多数情况下)的运行速度是2 倍apply(从角度来看的想法):

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;
    }   
};
Run Code Online (Sandbox Code Playgroud)

那么有谁知道为什么?

Nit*_*Nit 15

参考ECMAScript语言规范5.1版(2011年6月):

15.3.4.3 Function.prototype.apply(thisArg,argArray)

apply带有参数thisArg和argArray的对象func上调用该方法时,将执行以下步骤:

  1. 如果IsCallable(func)false,则抛出TypeError异常.

  2. 如果argArraynullundefined,那么 return调用[[Call]]内部方法的结果func,提供thisArg作为this值和空参数列表.

  3. 如果Type(argArray)不是Object,则抛出TypeError异常.
  4. 让我们len调用with参数的[[Get]]内部方法 .argArray"length"
  5. 我们nToUint32(len).
  6. 让我们argList空虚List.
  7. 让我们index为0.
  8. 重复一遍 index < n
  9. 我们indexNameToString(index).
  10. 让我们nextArg调用with 的[[Get]]内部方法 作为参数.argArrayindexName
  11. 追加nextArg为最后一个元素argList.
  12. 设置indexindex + 1.
  13. 返回调用[[Call]]内部方法的结果func,提供thisArg作为this值和argList参数列表.

15.3.4.4 Function.prototype.call(thisArg [,arg1 [,arg2,...]])

call使用参数thisArg和可选参数arg1,arg2等在对象func上调用该方法时,将执行以下步骤:

  1. 如果IsCallable(func)false,则抛出TypeError异常.
  2. 让我们argList空虚List.
  3. 如果使用多个参数调用此方法,则从左到右开始,arg1将每个参数作为最后一个元素追加argList
  4. 返回调用[[Call]]内部方法的结果func,提供thisArg作为this值和argList参数列表.

正如我们所看到的,apply指定的格式显着更重,并且由于需要更改参数的格式以及最终需要它们的方式,因此需要做更多的工作.由于输入格式的不同,
有许多检查apply不必要call.

另一个关键点是参数循环的方式(步骤4-12中apply,隐含在步骤3中call):apply无论实际有多少个参数,都执行整个循环设置,call所有这些都是只在需要时完成.
此外,值得注意的call是,没有指定实现步骤3的方式,这将有助于解释不同浏览器行为的巨大差异.

所以简要回顾:callapply输入参数已经格式化为内部方法所需的更快.

请务必阅读以下评论以进一步讨论.