Pourquoi la propriété arguments.callee.caller est-elle obsolète en JavaScript?

StackOverflow https://stackoverflow.com/questions/103598

  •  01-07-2019
  •  | 
  •  

Question

Pourquoi la propriété arguments.callee.caller est-elle obsolète en JavaScript?

Il a été ajouté, puis obsolète en JavaScript, mais il a été totalement omis par ECMAScript. Certains navigateurs (Mozilla, IE) l'ont toujours supporté et n'ont aucun plan sur la carte pour supprimer le support. D'autres (Safari, Opera) ont adopté le support, mais celui des navigateurs plus anciens n'est pas fiable.

Existe-t-il une bonne raison de mettre cette fonctionnalité précieuse en suspens?

(Ou alternativement, existe-t-il un meilleur moyen de saisir la poignée de la fonction d'appel?)

Était-ce utile?

La solution

Les premières versions de JavaScript n'autorisaient pas les expressions de fonction nommées et, pour cette raison, nous ne pouvions pas créer d'expression de fonction récursive:

 // 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é pour que nous puissions faire:

 [1,2,3,4,5].map(function(n) {
     return (!(n>1))? 1 : arguments.callee(n-1)*n;
 });

Cependant, c’était en fait une très mauvaise solution, car elle (associée à d’autres arguments, aux appels et aux problèmes des appelants) rend la récursion en ligne et la récursion impossibles dans le cas général (vous pouvez y parvenir dans certains cas grâce au traçage, etc. le meilleur code est sous-optimal en raison de vérifications qui ne seraient autrement pas nécessaires). L’autre problème majeur est que l’appel récursif aura un this valeur différent, 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();

Quoi qu'il en soit, EcmaScript 3 a résolu ces problèmes en autorisant les expressions de fonction nommées, par exemple:

.
 [1,2,3,4,5].map(function factorial(n) {
     return (!(n>1))? 1 : factorial(n-1)*n;
 });

Cela présente de nombreux avantages:

  • La fonction peut être appelée comme n'importe quelle autre depuis votre code.

  • Cela ne pollue pas l'espace de noms.

  • La valeur de this ne change pas.

  • C’est plus performant (accès à arguments objet est cher).

Oups,

Je viens de me rendre compte qu'en plus de tout le reste, la question concernait arguments.callee.caller , ou plus précisément Function.caller .

À tout moment, vous pouvez trouver le plus puissant appelant d'une fonction de la pile. Comme je l'ai dit plus haut, la pile d'appels n'a qu'un seul effet majeur: elle rend impossible un grand nombre d'optimisations, voire beaucoup plus. plus difficile.

Par exemple. si nous ne pouvons pas garantir qu'une fonction f n'appelle pas une fonction inconnue, il n'est pas possible d'inclure f en ligne. En gros, cela signifie que tout site d’appel qui aurait pu être inséré de manière triviale accumule un grand nombre de gardes, prenez:

 function f(a, b, c, d, e) { return a ? b * c : d * e; }

Si l'interpréteur js ne peut pas garantir que tous les arguments fournis sont des nombres au moment où l'appel est effectué, il doit insérer des vérifications pour tous les arguments avant le code en ligne ou ne pas insérer la fonction en ligne.

Dans ce cas particulier, un interpréteur intelligent devrait pouvoir réorganiser les contrôles de manière à être plus optimaux et ne pas vérifier les valeurs qui ne seraient pas utilisées. Toutefois, dans de nombreux cas, cela n’est tout simplement pas possible et, par conséquent, il devient impossible de s’inscrire en ligne.

Autres conseils

arguments.call ee .call er n'est pas déconseillé, bien qu'il utilise le < a href = "https://developer.mozilla.org/fr/Core_JavaScript_1.5_Reference/Global_Objects/Function/caller" rel = "noreferrer"> Fonction.call er propriété. ( arguments.call ee vous donnera simplement une référence à la fonction actuelle)

  • Function.call er , bien que non standard selon ECMA3, est implémenté sur tous les principaux navigateurs actuels .
  • arguments.call r est déconseillé en faveur de Function.call er et n'est pas implémenté dans les principaux navigateurs actuels ( par exemple Firefox 3).

La situation est donc loin d'être idéale, mais si vous souhaitez accéder à la fonction d'appel en Javascript sur tous les principaux navigateurs, vous pouvez utiliser la propriété Function.call er . , soit directement via une référence de fonction nommée, soit depuis une fonction anonyme via la propriété arguments.call ee .

Il est préférable d'utiliser des fonctions nommées plutôt que arguments.callee:

.
 function foo () {
     ... foo() ...
 }

est meilleur que

 function () {
     ... arguments.callee() ...
 }

La fonction nommée aura accès à son appelant via le appelant propriété:

 function foo () {
     alert(foo.caller);
 }

qui est meilleur que

 function foo () {
     alert(arguments.callee.caller);
 }

Cette dépréciation est due aux principes de conception actuels d'ECMAScript.

Juste une extension. La valeur de " this " changements pendant la récursion. Dans l'exemple suivant (modifié), factorial obtient l'objet {foo: true}.

[1,2,3,4,5].map(function factorial(n) {
  console.log(this);
  return (!(n>1))? 1 : factorial(n-1)*n;
},     {foo:true}     );

La factorielle appelée première fois récupère l'objet, mais ce n'est pas vrai pour les appels récursifs.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top