递归函数详解

Posted onebox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归函数详解相关的知识,希望对你有一定的参考价值。

1、什么是递归函数?

递归函数就是在一个函数通过名字调用自身的情况下构成的,

如下所示:我们用递归实现阶乘

    var factorial = function (num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * factorial(num - 1);
        }
    }

2、如何实现递归函数?

(1)先写一层的情况。上面所示的递归阶乘我们就可以先思考num参数乘num-1的情况。

(2)抽象递归参数。在递归函数中,如何将下一层关联起来就需要抽象参数来进行解决,参数的个数根据情况而定。

(3)找到突破点。为什么要找一个突破点?在js中你会发现很少有人写递归,因为不注意就会造成死循环。必须记住递归函数是自己调用自己,某种情况(这种情况肯定存在)不调用自己。在上面的递归函数中num<=1就是一个突破点。

3、上述代码存在的问题

    var anotherfactorial = factorial;
    factorial = null;
    console.log(anotherfactorial(3)); // factorial is not a function(出错)

为什么会出错呢?

以上代码先把factorial函数保存在变量anotherfactorial中,然后将factorial赋值为null。导致的结果指向原始函数的引用只剩下一个。但是接下来调用anotherfactorial时,由于必须执行factorial函数,而factorial这时候已经赋值为null了,所以就会导致错误。

那么如何解决这个问题呢?

在ECMAScript提供了arguments.callee可以解决这个问题。arguments.callee是一个指向正在执行的函数(anotherfactorial)的指针,因此可以用它来实现对函数的递归调用。例如上述代码我们就可以这样写:

    var factorial = function (num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * arguments.callee(num - 1);
        }
    }
    var anotherfactorial = factorial;
    factorial = null;
    console.log(anotherfactorial(3)); // 6

通过使用arguments.callee代替函数名,可以确保无论怎样调用函数都不会出问题。因此在使用递归函数时,使用arguments.callee总比使用函数名更保险。

但是在严格模式下,不能直接访问arguments.callee,并且会导致错误。所以产生了终极解决方案,使用命名函数表达式来达成相同的效果。例如:

    var factorial = (function f(num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * f(num - 1);
        }
    });
    var anotherfactorial = factorial;
    factorial = null;
    console.log(anotherfactorial(3)); // 6

在以上代码中创建了一个名为f的命名函数表达式,避免了出现arguments.callee。然后将它赋值给变量factorial。即使把函数赋值给另一个变量,函数的名字f仍然有效,所以递归调用照样能正确完成,而且这种方法在严格模式和非严格模式下都能运行。

以上是关于递归函数详解的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript关于函数部分详解以及几种特殊的函数(回调函数递归函数)

C#函数式编程中的递归调用之尾递归详解

nodejs常用代码片段

Python 递归函数 详解

递归函数详解

我在 laravel 中的递归函数不调用自己