Je peux créer une fonction récursive dans une variable comme ceci:
/* Count down to 0 recursively.
*/
var functionHolder = function (counter) {
output(counter);
if (counter > 0) {
functionHolder(counter-1);
}
}
Avec cela, functionHolder(3);
sortirait 3
2
1
0
. Disons que j'ai fait ce qui suit:
var copyFunction = functionHolder;
copyFunction(3);
produirait 3
2
1
0
comme ci-dessus. Si j'ai ensuite changé functionHolder
comme suit:
functionHolder = function(whatever) {
output("Stop counting!");
Puis functionHolder(3);
donnerait Stop counting!
, comme prévu.
copyFunction(3);
donne maintenant 3
Stop counting!
comme il se réfère functionHolder
, pas la fonction (à laquelle il pointe lui-même). Cela pourrait être souhaitable dans certaines circonstances, mais y a-t-il un moyen d'écrire la fonction de sorte qu'elle s'appelle elle-même plutôt que la variable qui la contient?
Autrement dit, est-il possible de changer uniquement la ligne de functionHolder(counter-1);
sorte que passer par toutes ces étapes donne encore 3
2
1
0
lorsque nous appelons copyFunction(3);
? J'ai essayé this(counter-1);
mais cela me donne l'erreur this is not a function
.
Réponses:
Utilisation d'expressions de fonction nommées:
Vous pouvez donner à une expression de fonction un nom qui est réellement privé et qui n'est visible que de l'intérieur de la fonction si elle-même:
Ici
myself
n'est visible qu'à l'intérieur de la fonction elle-même.Vous pouvez utiliser ce nom privé pour appeler la fonction de manière récursive.
Voir
13. Function Definition
la spécification ECMAScript 5:Veuillez noter qu'Internet Explorer jusqu'à la version 8 ne se comporte pas correctement car le nom est en fait visible dans l'environnement de la variable englobante, et il fait référence à un double de la fonction réelle (voir le commentaire de patrick dw ci-dessous).
En utilisant arguments.callee:
Vous pouvez également utiliser
arguments.callee
pour faire référence à la fonction actuelle:La 5ème édition d'ECMAScript interdit l'utilisation d'arguments.callee () en mode strict , cependant:
la source
myself
est en fait visible dans l'environnement de variable englobante, et il fait référence à un double de lamyself
fonction réelle . Vous devriez pouvoir définir la référence externe surnull
cependant.return n * myself(n-1);
?Vous pouvez accéder à la fonction elle-même en utilisant
arguments.callee
[MDN] :Cependant, cela cassera en mode strict.
la source
TypeError
, mais je n'ai rien trouvé qui déclare officiellement quearguments.callee
(ou toute violation du mode strict) est obsolète en dehors du "mode strict".Vous pouvez utiliser le combinateur Y: ( Wikipedia )
Et vous pouvez l'utiliser comme ceci:
la source
Je sais que c'est une vieille question, mais j'ai pensé présenter une autre solution qui pourrait être utilisée si vous souhaitez éviter d'utiliser des expressions de fonction nommées. (Ne pas dire que vous devriez ou ne devriez pas les éviter, simplement présenter une autre solution)
la source
Voici un exemple très simple:
Notez que le
counter
compte «à rebours» par rapport àslug
la valeur de. Cela est dû à la position à laquelle nous enregistrons ces valeurs, car la fonction se reproduit avant la journalisation - donc, nous continuons essentiellement à nous imbriquer de plus en plus profondément dans la pile d'appels avant la journalisation.Une fois que la récursion rencontre l'élément final de la pile d'appels, elle trampoline "hors" des appels de fonction, tandis que le premier incrément de
counter
se produit à l'intérieur du dernier appel imbriqué.Je sais que ce n'est pas un «correctif» sur le code du questionneur, mais étant donné le titre, j'ai pensé que je donnerais un exemple générique de récursion pour une meilleure compréhension de la récursivité, carrément.
la source