Je me demande si quelqu'un sait pourquoi l' call
est tellement plus rapide que l' apply
? Dans Chrome, il est approximativement 4 fois plus rapide, et 30x dans firefox, et je peux même créer un prototype personnalisé, apply2
, qui fait (dans la plupart des cas) exécuter 2 fois aussi rapidement que possible (l'idée tirée d'angulaire):
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; } };
Est-ce que quelqu'un sait pourquoi?
Référencement de l' édition ECMAScript Language Specification 5.1 (juin 2011) :
Lorsque la méthode d' apply
est appelée sur un objet func avec arguments thisArg et argArray, les étapes suivantes sont prises:
Si IsCallable(func)
est false
, lancez une exception TypeError
.
Si argArray
est null
ou undefined
, return
le résultat de l'appel de la méthode interne [[Call]]
de func
, fournissant thisArg
comme this
valeur et une liste d'arguments vide.
Type(argArray)
n'est pas Object
, lancez une exception TypeError
. len
être le résultat de l'appel de la méthode interne [[Get]]
de argArray
avec l'argument "length"
. n
ToUint32(len)
. argList
être une List
vide. index
être 0. index < n
indexName
être ToString(index)
. nextArg
être le résultat de la méthode interne [[Get]]
de argArray
avec indexName
comme argument. nextArg
comme dernier élément de argList
. index
sur l' index + 1
. [[Call]]
de func
, fournissant thisArg
comme la valeur et argList
comme la liste des arguments. Lorsque la méthode d' call
est appelée sur un objet func avec argument thisArg et arguments facultatifs arg1, arg2 etc., les étapes suivantes sont prises:
IsCallable(func)
est false
, lancez une exception TypeError
. argList
être une List
vide. arg1
ajoutez chaque argument comme dernier élément de argList
[[Call]]
de func
, fournissant thisArg
comme la valeur et argList
comme la liste des arguments. Comme nous pouvons le voir, le format dans lequel apply
est spécifié est particulièrement plus lourd et doit faire beaucoup plus en raison de la nécessité de changer le format dans lequel les arguments sont donnés et comment ils sont finalement nécessaires.
Un certain nombre de contrôles apply
ce qui n'est pas nécessaire dans l' call
raison de la différence de formatage des entrées.
Un autre point clé est la manière dont les arguments sont bouclés (les étapes 4-12 dans apply
, impliquées à l'étape 3 de l' call
): l'ensemble de la mise en boucle est exécuté en apply
quel que soit le nombre d'arguments existants, en call
Tout cela ne se fait que si nécessaire.
En outre, il est intéressant de noter que la façon dont l'étape 3 de l' call
est implémentée n'est pas spécifiée, ce qui aiderait à expliquer les différences drastiques dans les différents comportements du navigateur.
Pour rappeler à bref délai: l' call
est plus rapide que l' apply
car les paramètres d'entrée sont déjà formés au besoin pour la méthode interne.
Assurez-vous de lire les commentaires ci-dessous pour une discussion plus approfondie.