Comment l'utilisation d'une clause de retour avant un appel de fonction récursive diffère-t-elle d'une utilisation différente?

J'avais juste des expériences avec une récursivité et j'ai remarqué quelque chose qui me confondait. Permettez-moi d'illustrer avec quelques exemples de code:

function loop(x) { if (x >= 10) return x; loop(x + 1); // the recursive call } loop(0); 

L'appel ci-dessus retourne undefined . Si je change pour

 function loop(x) { if (x >= 10) return x; return loop(x + 1); // the recursive call } loop(0); 

Alors il retourne 10 correctement.

Pourquoi cela se produit-il? Comment la clause de return affecte-t-elle la pile?

PS: question similaire

EDIT: Voici une image rapide décrivant ce que j'ai compris. (Je n'ai absolument aucune peinture-fu.) Est-ce vrai? Sinon, où est-ce que j'ai mal tourné?

Si vous ne revenez pas d'une fonction Javascript, il existe implicitement un "retour indéfini" à la fin.

 function loop(x) { if (x >= 10) return x; loop(x + 1); // the recursive call return undefined; } 

Comme vous pouvez le voir, l'appel récursif est appelé et sa valeur de retour est ignorée. C'est comme ce qui se produit lorsque vous appelez une fonction comme console.log – la fonction est appelée et exécute tous les effets secondaires, mais vous supprimez la valeur de retour à la fin.

Lorsque vous utilisez la fonction sans la deuxième instruction de return , la fonction ne donne aucune valeur à l'appelant par définition dans les retours JavaScript undefined .

Donc, en utilisant la première définition et par exemple la loop(9) :

  1. 0 < 10 , donc nous n'exécutons pas le corps if -clause, mais appelons simplement la loop(10) .
  2. loop(10) renvoie 10 , mais nous n'utilisons jamais cette valeur.
  3. La boucle de fonction se termine et, comme aucune autre valeur n'a été renvoyée, elle retourne undefined .

Une fonction renvoie la valeur à son appelant immédiat. Puisque dans le cas de la loop(0) , la condition if n'est pas remplie, return x; N'est pas exécuté et la fonction n'a pas d'autre déclaration de return , elle ne renvoie rien.

Si vous l'appelez avec la loop(10) cela remplirait l'état et renverait 10 .

Dans le second cas, return loop(x + 1); Provoque une loop pour renvoyer tout l'autre appel à la loop retourne.

Peut-être est-il plus facile à comprendre avec un exemple non récursif:

 function bar() { return 42; } function foo1() { bar(); } function foo2() { return bar(); } // foo1(); // undefined foo2(); // 42 

foo1 appelle la bar , mais elle ne fait rien avec la valeur de retour. Étant donné qu'il n'y a pas d'énoncé de return à l'intérieur de foo , la fonction ne renvoie rien.

foo2 d'autre part renvoie la valeur de retour de la bar .

 function count_to_3 (x) { x = x || 0; if (x === 3) { return x; } return count_to_3(x + 1); } count_to_3(); 

C'est le même que dire quelque chose comme ceci:

 function add_1 (x) { return x + 1; } function count_to_3 () { var x = 0; x = add_1( add_1( add_1(x) ) ); return x; } count_to_3(); 

Chacune des fonctions add_1 effectue leur travail et renvoie leur valeur. La fonction interne est appelée en premier – elle ajoute 1 à x (commençant à 0 ) et renvoie sa valeur dans l' add_1 suivant, qui en ajoute une et la renvoie dans l' add_1 suivant.

… mais si vous ne renvoyez pas la valeur, rien ne se produira.

Avec récursion, c'est la même idée.

Vous retournez la valeur de retour de la fonction que vous appelez.

Vous n'avez pas besoin de faire cela.
Parfois, la récurrence consiste à traverser un arbre et à modifier les enfants – comme changer chaque second noeud DOM en rouge et changer le premier enfant de chaque noeud parent bleu …

Il n'y a pas de valeur de retour dont vous avez besoin.
Il suffit de configurer vos chèques, afin que vous n'essayez pas de réintroduire dans l'infini ou finissent par essayer de modifier les propriétés des choses qui n'existent pas.

Mais pour les caisses enregistreuses ou pour les boucles où vous voulez savoir si une valeur existe, alors ce que vous faites est identique à dire return add_1( add_1( add_1(0) ) ); , En supposant que add_1 renvoie sa valeur.

Toute fonction qui n'a pas d'instruction de retour renverra undefined (à moins qu'elle ne soit appelée avec une new , mais vous obtenez un nouvel objet, et cela ne vous aide pas non plus).

Si x <10, la fonction de boucle ne renvoie aucune valeur, 'pourquoi la return loop(x + 1); Vous donne "indéfini". Dès que vous atteignez 10, le return x; La déclaration commence et vous obtenez votre valeur retournée.

Le fait que vous l'utilisiez comme une fonction récursive ne fait aucune différence ici.

L'ordre dans lequel cet appel récursif évaluera sera à partir du dernier appel vers le bas. La fonction qui est évaluée en premier est la boucle (10) qui renvoie une valeur de 10. La prochaine sera la boucle (9) et ainsi de suite. Pensez à quelle boucle (9) ressemblera quand on l'appelle:

 loop(9) { if (x >= 10) return x; 10 } 

Loop (9) renverra indéfinie. Boucle (8) sera aussi … et ainsi de suite.

À l'inverse, si vous renvoyez la valeur de l'appel récursif, cela ressemblerait à ceci:

 loop(9) { if (x >= 10) return x; return 10 } 

Et au moment où votre appel de fonction initial est exécuté, il ressemblera à ceci:

 loop(0) { if (x >= 10) return x; return 10 } 

J'ai créé un jsfiddle pour démontrer le point: http://jsfiddle.net/TSnxp/