【问题标题】:Beginner's question about a recursion example in JS初学者关于JS中递归示例的问题
【发布时间】:2020-08-25 17:00:52
【问题描述】:

我是一名初学者,正在学习 JS 教程,但在这个递归函数示例中试图理解语句执行的顺序时遇到了困难:

function countup(n) {
  if (n < 1) {
    return [];
  } else {
    const countArray = countup(n - 1);
    countArray.push(n);
    return countArray;
  }
}
console.log(countup(5)); // Output is [ 1, 2, 3, 4, 5 ]

我假设,每次到达 const countArray = countup(n - 1); 行时,它都会将执行抛回第 1 行,并减少 n。这将解释从 1 开始向上的输出数组,而 n 正在下降。但在这种情况下,函数不应该只返回空数组 [],因为 n 会降到 1 以下,满足第一个 if 并在任何东西被推入 countArray (else) 之前终止? **尝试使用谷歌搜索断点以查看实际流程,但只看到它们在非循环中的使用

【问题讨论】:

  • 断点就是断点,不管它是否在循环中。 console.log 也可以成为你的朋友。但我不确定我是否理解您对正在发生的事情的解释:当countup(n - 1) 被击中时,该函数被调用 again 并在输入时使用 n 的新值。 n 不会小于一,直到...小于一,例如,第一次,它将是 4
  • IMO 你最好最好用铅笔和纸“玩电脑”——假装你是电脑,写下每一步,并记住执行将在递归调用 countup 后立即恢复,每次执行 countup
  • 特别注意每次调用时采用的条件分支。例如,对于第一次迭代,采用什么分支?返回了什么?对于第一次迭代,它是立即返回,还是进行递归调用?提示:你的笔/铅笔和纸练习,如果你缩进每个调用,大部分应该看起来像一个反斜杠。
  • const countArray = countup(n - 1); 不会将执行返回到第 1 行!它使用n-1 再次调用countup,一旦该调用返回,当前调用将继续并返回它自己的值。

标签: javascript recursion breakpoints


【解决方案1】:

让我们简单地假设每个函数调用及其所有信息都将存储在堆栈中。请注意,堆栈是 LIFO(后进先出)。

所以在您的代码中,countup(5) 将被调用并存储在 stack[0] 中。

然后在 else 条件中它再次被称为countup(4)。这将暂停 countup(5) 的执行,countup(4) 将存储在 stack[1] 中。

就像这样直到n&lt;1 countup 将被调用一个较低的值并存储在堆栈中。

在所有调用结束时,堆栈将是这样的,

 - stack[4]    countup(1)
 - stack[3]    countup(2)
 - stack[2]    countup(3)
 - stack[1]    countup(4)
 - stack[0]    countup(5)

现在将开始从堆栈中弹出。由于堆栈是 LIFO,因此堆栈顶部的元素将被弹出。弹出意味着您正在从堆栈中删除该元素。

countup(1) 将首先弹出并完成其执行。那是countArray.push(1)

然后countup(2) 将位于堆栈顶部。 因此,countup(2) 被弹出并完成其执行countArray.push(2)

就这样, countup(3) 被弹出并完成其执行countArray.push(3)countup(4) 被弹出并完成其执行 countArray.push(4)。 countup(5) 被弹出并完成其执行countArray.push(5)

最后返回整个数组。

*我已经简单地描述了它。幕后的真正执行还有很多事情要做,还有很多其他的术语要了解。 You can check this article that describes how recursion works in JS

【讨论】:

    【解决方案2】:

    我不知道你是否熟悉“spread”语法,但如果else 子句的主体写得简单,可能会更容易看出发生了什么:

    return [...countUp(n - 1), n];
    

    这只是意味着它是您通过获取 countUp(n - 1) 并在末尾添加元素 n 得到的数组。您显示的代码也是如此,只是方式略有不同。希望从这个描述中可以清楚地看出为什么该函数会做它所做的事情 - 但如果仍然不是,请注意:

    • countUp(0) 为空
    • countUp(1) 因此由一个空数组组成,末尾有一个额外的 1 - 所以单例数组 [1]
    • countUp(2) 是上面带有2 的结尾:[1, 2]

    等等。

    【讨论】:

      猜你喜欢
      • 2020-05-10
      • 2021-05-03
      • 1970-01-01
      • 2011-01-12
      • 2018-01-08
      • 2011-07-12
      • 1970-01-01
      • 2016-09-23
      • 1970-01-01
      相关资源
      最近更新 更多