1. 目的

  • 处理一些循环相关问题时,可以让代码更加简洁
  • 打开编程解题的一种思路,很多算法都会用到递归,包括汉诺塔、快速排序。

    2. 概念

    递归是函数的一种编程技巧,具体是指的调用函数本身。

    3. 限制

    递归需要设置边界:即什么时候结束。条件自己决定。

    1. //函数执行十次就结束
    2. function demo(num){
    3. if(num <1){return;}
    4. console.log(num);
    5. demo(num -1);
    6. }
    7. demo(10);

    4. 递归的经典应用

    计算某数的阶乘

    1. function factorial (num) {
    2. if (num == 1) {
    3. return 1
    4. }
    5. return num * factorial(num - 1)
    6. }
    7. console.log(factorial(5));//120

    求出斐波那契数列的第n项

    1. //斐波那契数列是指一堆有规律的数字,第一个和第二个都是1,从第三项开始,该项数字等于前两项之和: 1 1 2 3 5 8 13 21 34 …
    2. function fib (n) {
    3. n = parseInt(n);
    4. if (n < 1) {
    5. return 0
    6. }
    7. if (n == 1 || n == 2) {
    8. return 1
    9. }
    10. return fib(n - 1) + fib(n - 2)
    11. }
    12. console.log(fib(6));//8

    类似斐波那契数列问题

  • 台阶走法问题:有n个台阶,从第一阶开始走,每次可以走一个或两个台阶,问,到第n阶有多少中走法

  • 有一对雌雄兔子,从第三个月开始就每个月生一对雌雄兔子,新兔子又会在第三个月开始生,求第n月后有多少对兔子

    5. 传统递归的缺点

  • 不利于维护,在修改函数名的时候,需要修改两处,容易忘记,导致错误

  • 把函数指向其他变量,并清空原先函数的情况下,函数发生错误
    1. var anotherFunction = fatorial;
    2. factorial = null;
    3. alert(anotherFunction(4)); //出错

    6. arguments.callee

    使用 argumes.callee 可以解决这个问题。 arguments.callee 是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用。
    1. function factorial(num) {
    2. if (num <= 1) {
    3. return 1;
    4. }
    5. else {
    6. return num * arguments.callee(num - 1);
    7. }
    8. }
    通过 arguments.callee 代替函数名,可以确保无论怎样调用函数都不会出现问题。

    7. 命名函数表达式

    但在严格模式下,不能通过脚本访问 arguments.callee,访问这个属性会导致错误,不过可以使用命名函数表达式来达成相同的结果。
    1. var factorial = (function f(num) {
    2. if (num <= 1) {
    3. return 1;
    4. }
    5. else {
    6. return num * f(num - 1);
    7. }
    8. });