初学者关于JS中递归例子的问题

Beginner's question about a recursion example in JS

我是初学者,正在学习 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 向下。但在那种情况下,函数不应该只是 return 空数组 [],因为 n 会下降到 1 以下,满足第一个 if 并在任何东西被推入 countArray ( else)? **尝试谷歌搜索断点的使用以查看实际流程,但只看到它们在非循环中的使用

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

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

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

  • countUp(0)为空
  • countUp(1) 因此由一个空数组组成,最后还有一个 1 - 所以单例数组 [1]
  • countUp(2) 是上面的 2 最后:[1, 2]

等等。

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

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

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

就这样直到 n<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