🚝 JavaScript 函数递归与堆栈
# 函数递归
🌰 例子 / 使用递归简单实现计算 x
的 n
次方:
function pow(x, n) {
return (n == 1) ? x : x * pow(x, n - 1)
}
1
2
3
2
3
在 JavaSript 引擎中限制 最大递归深度(嵌套调用次数)。引擎在最大迭代深度为 10000 及以下时是可靠的,有些引擎可能允许更大的最大深度,但是对于大多数引擎来说,100000 可能就超出限制了。有一些自动优化能够帮助减轻这种情况(尾部调用优化),但目前它们还没有被完全支持,只能用于简单场景。
但是递归还是广泛应用,因为有很多事务使用递归更简洁并且更容易维护。
# 执行上下文和堆栈
执行上下文:有关正在运行的函数的执行过程的相关信息。
是一个内部数据结构,它包含有关函数执行时的详细细节:当前控制流所在的位置,当前的变量,
this
的值,以及其它的一些内部细节。一个函数调用 仅具有一个 与其相关联的 执行上下文。
进行函数的递归时,会发生:
- 当前函数被暂停;
- 与它关联的执行上下文被一个叫做 执行上下文堆栈 的特殊数据结构保存;
- 执行嵌套调用;
- 嵌套调用结束后,从堆栈中 恢复 之前的执行上下文,并从停止的位置恢复外部函数。
# 🍎 递归遍历
🌰 例子 / 公司部门人员结构:
let company = {
sales: [{
name: 'John',
salary: 1000
}, {
name: 'Alice',
salary: 1600
}],
development: {
sites: [{
name: 'Peter',
salary: 2000
}, {
name: 'Alex',
salary: 1800
}],
internals: [{
name: 'Jack',
salary: 1300
}]
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
一家公司有很多部门:
- 一个部门可能有一 数组 的员工;
- 一个部门可能会划分为几个子部门。
- 一个子部门增长时,它也有可能被拆分成几个子部门。
要循环完整个公司的员工信息,从第一层开始、到第二层 … 更多层。
使用 递归遍历 实现:
function sumSalaries(department) {
if (array.isArray(department)) {
return department.reduce((prev, cur) => {
prev += cur.salary
}, 0)
} else {
let sun = 0
for(let subDep of Object.values(department)) {
sum += sumSalaries(subDep)
}
}
return sum
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
编辑 (opens new window)
📢 上次更新: 2022/09/02, 10:18:16