继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

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

慕莱坞1975833
关注TA
已关注
手记 8
粉丝 90
获赞 468

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引擎的垃圾回收机制回收

打开App,阅读手记
2人推荐
发表评论
随时随地看视频慕课网APP