【问题标题】:Why does this recursive function return undefined?为什么这个递归函数返回未定义?
【发布时间】:2019-07-16 14:11:17
【问题描述】:

我正在尝试编写一个使用递归组合两个字符串的函数。我的代码在下面,但我不知道为什么函数返回 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

【问题讨论】:

  • msdn.microsoft.com/en-us/library/wwbyhkx4(v=vs.94).aspx 这有一个很好的基本示例。正如其他人所说,return 应该可以解决问题。
  • 除了在替代情况下缺少return 之外,您已经污染了,因此连续调用将返回以最后一个结果为前缀的结果。例如。 merge("CDE","123"); //==> "ABABABC1D2E3"
  • 您是否尝试过使用调试器遍历您的代码?那很快就会出现问题。
  • 合并递归调用前,检查函数返回的字符数是否大于1。

标签: javascript recursion


【解决方案1】:

说明

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

让我一步一步地带你了解执行过程:

  1. 带有参数"AAA""BBB",它们的长度不为0,转到其他。在 else 中,str3"AB",请致电 merge("AA", "BB")
  2. 带有参数"AA""BB",它们的长度不为0,转到其他。在 else 中,str3 现在是 "ABAB",请致电 merge("A", "B")
  3. 带有参数"A""B",它们的长度不为0,转到其他。在 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 分支中没有 return 语句,因此返回 undefined。解决所有调用后,返回undefined


解决方案

解决方案是简单地将return 添加到您的递归调用中。这样,每次调用的结果都会被返回,将str3 的最终返回值“委托”到调用堆栈上——调用返回"ABABAB",而不是undefined

由于我们现在返回调用结果,上面的步骤 6、7 和 8现在有一个返回语句。这意味着我们不返回undefined,而是返回str3。这是因为merge("", "") 返回了"ABABAB",也就是str3 的值。然后在调用merge("A", "B") 中返回该结果,因为新添加了return 语句,然后在调用merge("AA", "BB") 中返回,以此类推,直到调用完全解决,并返回str3 的值.

这是新代码:

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。由于我们现在返回递归调用,因此所有内容都相应返回,因此返回 str3 的值,并将其存储到变量 mergeString 中。

【讨论】:

    【解决方案2】:

    正如您在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")
    

    【讨论】:

    • "你必须使用关键字return 来调用递归函数" --- 这是危险的不精确。 return 用于从函数返回,调用某些东西。
    猜你喜欢
    • 1970-01-01
    • 2019-12-20
    • 2021-03-23
    • 1970-01-01
    • 2011-05-07
    • 2012-09-26
    相关资源
    最近更新 更多