なぜコールは適用よりずっと速いのでしょうか? 質問する

なぜコールは適用よりずっと速いのでしょうか? 質問する

誰か知っている人はいるだろうかなぜ callは よりもはるかに高速ですapply。Chrome では約 4 倍、Firefox では 30 倍高速です。また、カスタム プロトタイプ も作成できます。apply2これは (ほとんどの場合) の 2 倍の速度で実行されますapply(Angular から得たアイデア)。

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;
    }   
};

それで、誰か理由を知っていますか?

ベストアンサー1

参照ECMAScript 言語仕様 5.1 版 (2011 年 6 月):

15.3.4.3 関数プロトタイプを適用 (thisArg、argArray)

applyメソッドが引数 thisArg と argArray を持つオブジェクト func に対して呼び出されると、次の手順が実行されます。

  1. IsCallable(func)の場合falseTypeError例外をスローします。

  2. またはargArrayの場合、を値として、空の引数リストを指定して の内部メソッドを呼び出した結果になります。nullundefinedreturn[[Call]]functhisArgthis

  3. Type(argArray)そうでない場合Objectは例外をスローしますTypeError
  4. を引数 での内部メソッドlenを呼び出した結果とします。[[Get]]argArray"length"
  5. nとしますToUint32(len)
  6. argListを空の としますList
  7. を0としますindex
  8. 繰り返しながらindex < n
  9. indexNameとしますToString(index)
  10. を引数として の内部メソッドnextArgを呼び出した結果を とします。[[Get]]argArrayindexName
  11. nextArgの最後の要素として追加しますargList
  12. indexに設定index + 1
  13. を値として、 を引数リストとして指定して、[[Call]]の内部メソッドを呼び出した結果を返します。functhisArgthisargList

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

call引数 thisArg とオプションの引数 arg1、arg2 などを持つオブジェクト func でメソッドが呼び出されると、次の手順が実行されます。

  1. IsCallable(func)の場合falseTypeError例外をスローします。
  2. argListを空の としますList
  3. このメソッドが複数の引数で呼び出された場合は、左から右の順にarg1各引数を最後の要素として追加します。argList
  4. を値として、 を引数リストとして指定して、[[Call]]の内部メソッドを呼び出した結果を返します。functhisArgthisargList

ご覧のとおり、 でapply指定される形式は著しく重く、引数が与えられる形式とそれらが最終的に必要とされる方法を変更する必要があるため、より多くの処理が必要になります。入力フォーマットの違いにより、では必要のない
チェックがいくつかあります。applycall

もう 1 つの重要な点は、引数をループする方法です ( のステップ 4 ~ 12 apply、 のステップ 3 に暗示されていますcall)。 ループのセットアップ全体は、apply実際の引数の数に関係なく で実行され、 ではcall必要な場合にのみ実行されます。
また、 のステップ 3 の実装方法が指定されていないことも注目に値します。callこれは、さまざまなブラウザーの動作の大幅な違いを説明するのに役立ちます。

簡単にまとめると、入力パラメータが内部メソッドに必要なフォーマットに既に設定されているため、callは よりも高速です。apply

さらなる議論については、以下のコメントを必ずお読みください。

おすすめ記事