为了账号安全,请及时绑定邮箱和手机立即绑定

大前端开发之ES6尾调用优化

1、尾调用概念:尾调用指的是函数作为另外一个函数的最后一条语句被调用。
示例代码:

function demo(){
   return demoAnother();//尾调用
 }

2、ES5引擎环境中,尾调用底层实现机制:创建一个新的栈帧,将其推入调用栈来表示函数调用。也就是说,在循环调用中,每一个未用完的栈帧都会保存在内存中,当调用栈变得过大时会造成程序问题。
3、ES6引擎环境中,尾调用底层实现机制:ES6缩减了严格模式下尾调用栈的大小,当满足以下条件时,尾调用不再创建新的栈帧,而是清除并重用当前栈帧:
a、尾调用不访问当前栈帧的变量(就是说函数不是一个闭包)
b、在函数内部,尾调用是最后一条语句
c、尾调用的结果作为函数值返回
满足条件的示例代码:

function demo(){
    return demoAnother()
}

不满足条件的示例代码:
a、不返回最终结果

   function demo(){
      demoAnother();
   }

b、尾调用返回后执行其它操作

   function demo(){
      return 1+demoAnother();
   }

尾调用的主要应用场景是递归函数:

function factorial(n){
    if(n<=1){
        return 1;
    }else{
        //这个常见的阶乘函数无法实现尾优化,因为其在返回后执行乘法操作
        return n*factorial(n-1);
    }
}

以上代码当n的数值非常大时,调用栈将不断增长,从而导致栈溢出。
让我们来优化下这个尾调用:

function factorial(n,p=1){
    if(n<=1){
        return 1*p;
    }else{
        let result=n*p;
        //优化后
        return factorial(n-1,result);
    }
}

在这个函数中,第二个参数p的默认值为1,我们用他来保存乘法结果,下一次迭代中可以取出它用于计算,不再需要额外的函数调用。当n>1时,先执行一轮乘法计算,然后将结果传递给第二次factorial()调用的参数。
下面解释下为什么这样满足了尾调用优化条件的第一个条件:
有的同学说return 语句使用了result变量,这是一个闭包。请注意,我们使用的是let声明而不是var,使用let声明的变量只在当前代码块有用,当出了当前代码块,会被js引擎的垃圾回收机制回收

点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消