Pourquoi cette fonction récursive n'est-elle pas définie?

Je tente d'écrire une fonction qui combine deux chaînes en utilisant la récursivité. Mon code est ci-dessous, mais je ne sais pas pourquoi la fonction retourne indéfinie surtout lorsque je console.log dans le boîtier de base et qu'il n'imprime pas défini, mais plutôt la valeur correcte.

var str3="" function merge(str1,str2){ if(str1.length==0||str2.length==0){ console.log(str3) return str3; } else{ str3=str3+str1.substring(0,1)+str2.substring(0,1); merge(str1.substring(1,str1.length),str2.substring(1,str2.length)) } } merge("AAA","BBB") //--> returns undefined but the console.log(str3) gives correct answer 

Explication

Le problème est que vous ne renvoyez pas le résultat de l'appel récursif, donc il est indéfini lorsque l'appel complet à merge est résolu.

Permettez-moi de vous faire passer par l'exécution, étape par étape:

  1. Avec les arguments "AAA" et "BBB" , leurs longueurs ne sont pas 0, aller à autre chose. Une fois, str3 est "AB" , merge("AA", "BB") appel merge("AA", "BB") .
  2. Avec les arguments "AA" et "BB" , leurs longueurs ne sont pas 0, aller plus loin. Une fois, str3 est maintenant "ABAB" , merge("A", "B") appel merge("A", "B") .
  3. Avec les arguments "A" et "B" , leurs longueurs ne sont pas 0, aller plus loin. Une fois, str3 est maintenant "ABABAB" , merge("", "") appels merge("", "") .
  4. Avec les arguments de chaîne vide, la longueur est 0. Maintenant, passez à l'instruction if, où str3 est enregistré et renvoyé.
  5. Étant donné que l'appel de merge("", "") a résolu (pour "ABABAB" tel qu'il est renvoyé), nous continuons là où nous l'avons laissé dans la merge("A", "B") appel merge("A", "B") , donc "haut" le Pile d'appel.
  6. Nous commençons où nous avons laissé en merge("A", "B") appels merge("A", "B") , dans la branche else. Il n'y a plus de déclarations ou d'expressions dans cet appel, donc c'est résolu. Il n'y a pas de déclaration, donc, par défaut, il renvoie undefined . Nous allons "haut" la pile d'appel pour appeler merge("AA", "BB") où nous avons laissé.
  7. Nous commençons par où nous avons laissé en merge("AA", "BB") appel merge("AA", "BB") , dans la branche else. Il n'y a plus de déclarations ou d'expressions dans cet appel, donc c'est résolu. Encore une fois, il n'y a pas de déclarations de retour, par défaut, il renvoie undefined . Nous allons "haut" la pile d'appel pour appeler merge("AAA", "BBB") où nous avons laissé.
  8. Nous commençons où nous avons laissé en merge("AAA", "BBB") appels merge("AAA", "BBB") , dans la branche else. Il n'y a plus de déclarations ou d'expressions dans cet appel, donc c'est résolu. Encore une fois, il n'y a pas de déclarations de retour, par défaut, il renvoie undefined . Il n'y a plus d'appels, donc tout est résolu – et merge("AAA", "BBB") renvoie undefined .

TL; DR: l'appel récursif n'est pas retourné sur chaque appel dans la branche else, de sorte que la valeur de str3 est retournée à la merge("A", "B") appel merge("A", "B") . La merge("A", "B") appel merge("A", "B") ne renvoie rien, elle revient undefined . Il en va de même pour tous les autres appels – ils n'ont pas de déclaration dans la branche else, si undefined est renvoyé. Lorsque tous les appels sont résolus, undefined est renvoyé.


Solution

La solution consiste simplement à préciser le return à vos appels récursifs. De cette façon, le résultat de chaque appel serait renvoyé, 'déléguant' la valeur finale retournée de str3 jusqu'à la pile d'appel – l'appel renvoie "ABABAB" , non undefined .

Puisque nous renvoyons le résultat de l'appel, les étapes 6, 7 et 8 ci-dessus ont maintenant une déclaration . Cela signifie que nous ne retournons pas undefined , mais plutôt str3 . C'est parce que la merge("", "") renvoyé "ABABAB" , qui est la valeur de str3 . Ce résultat est ensuite renvoyé dans la merge("A", "B") appel merge("A", "B") raison de la nouvelle déclaration de return ajoutée, puis retournée dans la merge("AA", "BB") appels merge("AA", "BB") , etc., jusqu'à ce que l'appel soit str3 résolu, et le retourne la valeur de str3 .

Voici le nouveau code:

 var str3 = ""; function merge(str1, str2) { if(str1.length == 0 || str2.length == 0) { console.log(str3); return str3; } else { str3 = str3 + str1.substring(0, 1) + str2.substring(0, 1); return merge(str1.substring(1, str1.length), str2.substring(1, str2.length)); //we return the recursive call } } var mergedString = merge("AAA","BBB"); //mergedString is "ABABAB" 

Comment vous pouvez voir dans ce guide vous devez return la fonction récursive:

 var str3="" function merge(str1,str2){ if(str1.length==0||str2.length==0){ console.log(str3) return str3; } else{ str3=str3+str1.substring(0,1)+str2.substring(0,1); return merge(str1.substring(1,str1.length),str2.substring(1,str2.length)) } } merge("AAA","BBB")