Les premières versions de JavaScript ne permet pas nommé les expressions de fonction, et ce parce que nous ne pouvions pas faire une fonction récursive expression:
// This snippet will work:
function factorial(n) {
return (!(n>1))? 1 : factorial(n-1)*n;
}
[1,2,3,4,5].map(factorial);
// But this snippet will not:
[1,2,3,4,5].map(function(n) {
return (!(n>1))? 1 : /* what goes here? */ (n-1)*n;
});
Pour contourner ce problème, arguments.callee
a été ajouté, de sorte que nous pourrions faire:
[1,2,3,4,5].map(function(n) {
return (!(n>1))? 1 : arguments.callee(n-1)*n;
});
Cependant, c'était effectivement une très mauvaise solution comme ceci (en conjonction avec d'autres arguments, appelant, et des problèmes de l'appelant) faire de l'in-lining et la queue de la récursivité impossible dans le cas général (vous pouvez la réaliser en cas de sélection par le biais de traçage, etc, mais même le meilleur code est sous-optimale en raison de contrôles qui autrement ne seraient pas nécessaires). L'autre problème majeur est que l'appel récursif obtiendrez un autre this
de la valeur, par exemple:
var global = this;
var sillyFunction = function (recursed) {
if (!recursed)
return arguments.callee(true);
if (this !== global)
alert("This is: " + this);
else
alert("This is the global");
}
sillyFunction();
De toute façon, EcmaScript 3 résolu ces problèmes en permettant nommé les expressions de fonction, par exemple:
[1,2,3,4,5].map(function factorial(n) {
return (!(n>1))? 1 : factorial(n-1)*n;
});
Cela a de nombreux avantages:
La fonction peut être appelée comme toutes les autres à partir de l'intérieur de votre code.
Il ne pollue pas l'espace de noms.
La valeur de this
ne change pas.
Il est plus performant (l'accès à l' objet arguments est cher).
Oups,
Viens de réaliser que, en plus de tout le reste, la question était de savoir arguments.callee.caller
, ou plus précisément Function.caller
.
À n'importe quel point dans le temps, vous pouvez trouver le plus profond de l'appelant de la fonction sur la pile, et comme je l'ai dit ci-dessus, en regardant la pile d'appel a un effet majeur: Il fait un grand nombre d'optimisations impossible, ou beaucoup, beaucoup plus difficile.
Par exemple. si nous ne pouvons pas garantir qu'une fonction f
ne seront pas appeler une fonction inconnue, alors il n'est pas possible de inline f
. Fondamentalement, cela signifie que n'importe quel site d'appel qui peuvent avoir été trivialement inlinable accumule un grand nombre de gardes, de prendre:
function f(a, b, c, d, e) { return a ? b * c : d * e; }
Si le js interprète ne peut pas garantir que tous les arguments sont des nombres au point que l'appel est effectué, il doit insérer des contrôles pour tous les arguments avant de les inline code, ou s'il ne peut inline de la fonction.
Maintenant, dans ce cas particulier, un interprète intelligente devrait être en mesure de réorganiser les contrôles pour être plus optimale et de ne pas vérifier toutes les valeurs qui ne seraient pas utilisés. Cependant, dans de nombreux cas, c'est juste pas possible et, par conséquent, il devient impossible de la ligne.