【JavaScript入门笔记05 函数进阶Ⅰ 递归和堆栈】

笔记参考javascript.info中文站

递归和堆栈

函数内调用自身就是递归

1. 两种思考方式
  • for 循环迭代
  • 递归调用

第一种方式很简单不说,第二种递归调用有本质的不同

举个例子:

function pow(x, n) {
   
  if (n == 1) {
   
    return x;
  } else {
   
    return x * pow(x, n - 1);
  }
}

alert( pow(2, 3) ); // 8

通过递归实现数字的幂次运算,可以看到函数内有两个分支:

  • n == 1 时,返回 x 本身,递归结束
  • 其他情况,返回 x * 函数递归调用,递归继续,但标志变量 n 减一

也就是说,递归函数实际上将问题不断分化成更细小简单的问题,直到最原始的初态,而每个函数都有个判定标准,每次递归时会判断这个标准是否到了最简化状态,从而可以停止递归

最大的嵌套调用次数(包括首次)被称为 递归深度,Javascript 可靠的深度范围是在 10000 以内

2. 执行上下文和堆栈

递归调用过程的底层原理是什么样的呢?

在递归函数运行中,函数有关的信息会存储在 “执行上下文” 这个数据结构中,函数执行中所有的详细细节都会放在其中

事实上,这个过程有点类似计算机组成原理的中断,只不过中断后处理的结果会返回给原操作(函数):

  • 当前函数被暂停;
  • 与它关联的执行上下文被一个叫做 执行上下文堆栈 的特殊数据结构保存;
  • 执行嵌套调用;
  • 嵌套调用结束后,从堆栈中恢复之前的执行上下文,并从停止的位置恢复外部函数。

当然,递归不能是无限的,最好控制在 10000 以内,因此函数就需要一个 “出口”,也就是函数结束的条件,如上个例子中 n == 1 就是一个出口

在这之前,所有信息都会存储在 “执行上下文” 堆栈

此外,任何递归都可以被重写成循环形式,有的时候这种重写可以提高效率或者可读性,但递归的写法非常简洁,转化成循环形式可能反而变得复杂,尤其是 “出口” 或 “分支” 多的时候


3. 递归遍历

递归的另一个重要应用就是递归遍历。

如果遍历对象只是普通对象或者简单数组,一个循环就可以完成遍历,但如果遍历对象含有嵌套内容哪可能就会相对麻烦,如果嵌套层数过多,就需要递归遍历来解决嵌套遍历问题

递归遍历和递归函数的本质思想都是 “划分子问题” ,将整体拆解成最简单的初态再处理,最后层层返回

举个例子:

let company = {
    // 这是一个公司的人力管理图,有子部门嵌套,现在我们要求所有人的薪资总数
  sales: [{
   name: 'John', salary: 1000}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值