目录

🚝 JavaScript 函数递归与堆栈

# 函数递归

🌰 例子 / 使用递归简单实现计算 xn 次方:

function pow(x, n) {
  return (n == 1) ? x : x * pow(x, n - 1)
}
1
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

一家公司有很多部门:

  • 一个部门可能有一 数组 的员工;
  • 一个部门可能会划分为几个子部门。
  • 一个子部门增长时,它也有可能被拆分成几个子部门。

要循环完整个公司的员工信息,从第一层开始、到第二层 … 更多层。

使用 递归遍历 实现:

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
📢 上次更新: 2022/09/02, 10:18:16