递归函数是一个函数通过名字调用自身的情况下构成的,说到递归调用最常见的就是求阶乘了:
1 2 3 4 5 6 7 |
function factorial(num){ if (num <= 1){ return 1; } else { 6 return num * factorial(num-1); } } |
这是一个经典的递归阶乘函数。虽然看起来没有问题,但下面的代码却可能导致出错。
1 2 3 |
var anotherFactorial = factorial; factorial = null; alert(anotherFactorial(4)); //报错 |
以上代码先把factorial()
函数保存在变量anotherFactorial
中,然后将factorial
变量设为null,结果指向原始函数的引用只剩下一个。但在接下来调用anotherFactorial()
时候,由于函数内部必须要执行factorial() (num * factorial(num-1)),而factorial
已经不再是函数,所以会导致出错。
还有一种情况就是当我们的代码文档很复杂的时候,重命名一个递归函数,而忘记了修改实现中调用自身函数名的地方,也会导致报错
在这种情况下使用arguments.callee
可以解决这个问题
我们知道arguments.callee
是一个指向正在执行的函数的指针,因为可以用它来实现函数的递归调用,例如:
1 2 3 4 5 6 7 |
function factorial(num){ if (num <= 1){ return 1; } else { 6 return num * arguments.callee(num-1); } } |
通过调用arguments.callee
代替函数名,可以确保无论怎样调用函数都不会出问题,因此,在编写递归函数时,使用arguments.callee
比使用函数名更保险一些。
但是在严格模式下,不能通过脚本访问arguments.callee
,会导致错误,可以使用命名函数表达式来达成同样的效果。例如:
1 2 3 4 5 6 7 |
var factorial = (function f(num){ if (num<=1){ return 1; }else{ return num * f(num-1); } }); |
以上代码创建了一个名为f()
的命名函数表达式,然后将它赋值给变量factorial
。即便把函数赋值给了另外一个变量,函数的名字仍然有效,所以递归调用正确执行。这种方式在严格模式与非严格模式下都行得通
转载请注明:天狐博客 » javascript递归调用,递归函数