初学者关于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
我是初学者,正在学习 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