js中递归写法的逐步优化

递归有很多用法例如阶乘、二分查找等,这里以阶乘来做范例。

1.原始的递归表达式通常这样写:

    function fun(num) {
    if(num<=1) {
return 1;
}else {
return fun(num-1);
}

}

       

但是这种写法有一个问题:当函数名复制给其他的变量,然后将该函数名复制为其他值或null,执行被赋值的变量函数,则函数实效。即:
        var fun2 = fun;
fun = null;

fun2();//报错

2.解决上述问题:用arguments.callee()来代替函数内部那个指向自身的函数。

     function fun(num) {
if(num<=1) {
return 1;
}else {
return arguments.callee(num-1);
}

}

缺点:但是在严格模式下,脚本不能访问arguments.callee,访问这个属性会出错。

3.解决上述问题:使用命名函数表达式达到相同的结目的

    var fun = (function f(num) {

    if(num<=1) {

        return 1;

    }else {

        return num*f(num-1);    

}

});

以上代码创建了一个名为f()的命名函数表达式,然后将它赋值给变量fun,即使把函数赋值给其他变量,函数 名字f依然有效,所以递归调用照样能完成。而且无论在严格模式还是在非严格模式下都能实现。


4、不过以上写法都不是终极优化版本,由于以上递归写法中都使用了尾调用(尾调用就是指函数作为另一个函数的最后一条语句被调用),在ES5引擎中,尾调用的实现与其他函数调用的实现类似:创建一个新的栈帧,将其推入调入栈来表示函数调用。即在循环调用中,每一个未使用完的栈帧都会被保存在内存中,当调用栈变得过大就会造成程序问题。这也是以上所有递归写法都存在一个问题。

下边这种方法是在ES6中关于尾调用优化的一种方法:es6中缩减了严格模式下尾调用栈的大小(非严格模式不影响),如果满足下列三个条件尾调用不再创建新的栈帧,而是清除并重用当前栈帧。

*尾调用不是闭包,不访问当前栈帧的变量。

*在函数内部,尾调用是最后一条语句,且不能进行其他运算操作。

*尾调用的结果作为函数值返回。

也就是下列这种形式就可被javaScript引擎自动优化:

"use strict";
function fun(num,k=1) {
if(num<=1) {
return 1*k;
}else {
let result = num*k;
return fun(num,result);
}

}

在写递归函数的时候,如果递归函数的运算量足够大使用尾调用可以大幅提升程序性能。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值