誰か知っている人はいるだろうかなぜ 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 に対して呼び出されると、次の手順が実行されます。
IsCallable(func)
の場合false
はTypeError
例外をスローします。または
argArray
の場合、を値として、空の引数リストを指定して の内部メソッドを呼び出した結果になります。null
undefined
return
[[Call]]
func
thisArg
this
Type(argArray)
そうでない場合Object
は例外をスローしますTypeError
。- を引数 での内部メソッド
len
を呼び出した結果とします。[[Get]]
argArray
"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
argList
15.3.4.4 Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )
call
引数 thisArg とオプションの引数 arg1、arg2 などを持つオブジェクト func でメソッドが呼び出されると、次の手順が実行されます。
IsCallable(func)
の場合false
はTypeError
例外をスローします。argList
を空の としますList
。- このメソッドが複数の引数で呼び出された場合は、左から右の順に
arg1
各引数を最後の要素として追加します。argList
- を値として、 を引数リストとして指定して、
[[Call]]
の内部メソッドを呼び出した結果を返します。func
thisArg
this
argList
ご覧のとおり、 でapply
指定される形式は著しく重く、引数が与えられる形式とそれらが最終的に必要とされる方法を変更する必要があるため、より多くの処理が必要になります。入力フォーマットの違いにより、では必要のない
チェックがいくつかあります。apply
call
もう 1 つの重要な点は、引数をループする方法です ( のステップ 4 ~ 12 apply
、 のステップ 3 に暗示されていますcall
)。 ループのセットアップ全体は、apply
実際の引数の数に関係なく で実行され、 ではcall
必要な場合にのみ実行されます。
また、 のステップ 3 の実装方法が指定されていないことも注目に値します。call
これは、さまざまなブラウザーの動作の大幅な違いを説明するのに役立ちます。
簡単にまとめると、入力パラメータが内部メソッドに必要なフォーマットに既に設定されているため、call
は よりも高速です。apply
さらなる議論については、以下のコメントを必ずお読みください。