JS高级进阶——递归

递归: 函数在运行过程中自己调用自己
递归算法的基本思想是:把规模大的、较难解决的问题变成规模较小的、易解决的同一问题。规模较小的问题又变成规模更小的问题,并且小到一定程度可以直接得出它的解,从而得到原来问题的解。
看一个典型的求阶乘的栗子:

 function fun(n) {
        if (n<=1) {
          return 1;
        }else {
          return n*fun(n-1);
        }
      }
      fun(3);

但这样有个缺点:
我们知道函数名是指向函数对象的指针,如果把函数的名与函数对象本身的指向关系断开,此方式将无法找到正确的指向。

//切断函数名关联
		var newff = fun;
       fun= null;
        newff()// 报错

在这里插入图片描述
如何优化呢?我们可以通过arguments.callee来代替函数名,可以确保无论怎样调用函数都不会出问题。

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

但在严格模式(use strict)下,不能通过脚本访问arguments.callee,访问这个属性会导致错误。不过,可以使用命名函数表达式(内联函数)来达成相同的结果:

var fun = (function fun1(n) {
        if (n<=1) {
          return 1;
        }else {
          return n*fun1(n-1);
        }
      });

但其实类似求阶乘的问题并不适合用递归,因为它的运行需要较多次数的函数调用,如果调用层数比较深,每次都要创建新的变量,需要增加额外的堆栈处理,会对执行效率有一定影响,占用过多的内存资源。还有一种解决办法是尾递归

function fun(n,total=1{
	if(n===1)return total;
	return fun(n-1,n*total);
}

这样,每一次返回的就是一个新的函数,不带上一个函数的参数,也就不需要储存上一个函数了。

一个问题要采用递归方法来解决时,必须符合以下三个条件:

1.解决问题时,可以把一个问题转化为一个新的问题,而这个新的问题的解决方法仍与原问题的解法相同,只是所处理的对象有所不同,这些被处理的对象之间是有规律的递增或递减;

2.可以通过转化过程是问题得到解决;

3.必定要有一个明确的结束递归的条件,否则递归将会无止境地进行下去,直到耗尽系统资源。也就是说必须要某个终止递归的条件。

你可能感兴趣的:(JavaScript,前端学习)