为什么这个递归函数返回undefined?

5

我正在尝试编写一个使用递归来合并两个字符串的函数。以下是我的代码,但我不知道为什么该函数返回undefined,特别是当我在基本情况下使用console.log时,它不会打印undefined,而是正确的值。

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

https://msdn.microsoft.com/zh-cn/library/wwbyhkx4(v=vs.94).aspx 这里有一个很好的基本示例。正如其他人所说,return应该可以解决问题。 - user3366016
除了在备选情况下缺少return之外,您还会使连续调用返回以最后一个结果为前缀的结果。例如:merge("CDE","123"); //==> "ABABABC1D2E3" - Sylwester
你尝试使用调试器逐步执行代码了吗?这样很快就能找出问题所在。 - user663031
在合并递归调用之前,您需要检查字符数是否大于1,否则从函数返回。 - Balasubramaniyan Ramadoss
2个回答

11

解释

问题在于你没有返回递归调用的结果,因此当整个对merge的调用被解决时,它是未定义的。

让我一步一步地带你执行:

  1. 使用参数"AAA""BBB",它们的长度不为0,进入else。 一旦在else中,str3"AB",调用merge("AA","BB")
  2. 使用参数"AA""BB",它们的长度不为0,进入else。 一旦在else中,str3现在是"ABAB",调用merge("A", "B")
  3. 使用参数"A""B",它们的长度不为0,进入else。 一旦在else中,str3现在是"ABABAB",调用merge("","")
  4. 具有空字符串参数,长度为0. 现在转到if语句,在这里记录并返回str3
  5. 由于merge ("","")调用已被解决(返回"ABABAB"),因此我们继续在调用merge("A", "B")中离开的地方,从而向上移动调用堆栈。
  6. 我们从调用merge("A", "B")中离开的地方开始,在else分支中。 该调用中没有更多的语句或表达式,因此已解决。 没有返回语句,因此默认情况下返回 undefined 。 我们回到调用merge("AA","BB")的位置,停留在我们离开的地方。
  7. 我们从调用merge("AA","BB")中离开的地方开始,在else分支中。 该调用中没有更多的语句或表达式,因此已解决。 再次,没有返回语句,因此默认情况下返回undefined。 我们回到调用merge("AAA", "BBB")的位置,停留在我们离开的地方。
  8. 我们从调用merge("AAA", "BBB")中离开的地方开始,在else分支中。 该调用中没有更多的语句或表达式,因此已解决。 再次,没有返回语句,因此默认情况下返回 undefined 。 没有更多的调用,因此一切都解决了-merge("AAA","BBB")返回 undefined

TL;DR:在else分支中递归调用没有被返回,因此str3的值将返回给merge("A", "B")调用。 调用merge("A", "B")不返回任何内容,它返回undefined。 所有其他调用也是如此-它们在else分支中没有返回语句,因此返回undefined。 当所有调用都已解决时,返回undefined


解决方案

解决方案很简单,只需在递归调用之前

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"

在此之前,mergedString 的值将为 undefined。现在我们返回递归调用的结果,这样一来所有内容都会按照预期返回,因此变量 mergeString 存储了 str3 的值。


0

正如你在this指南中所看到的,你需要return递归调用的结果:

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")

3
你需要使用关键词 return 来调用递归函数。这种表述不够精准,return 是用于从函数中返回结果的,而不是用于调用某些东西。 - zerkms

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接