递归函数是在一个函数通过名字调用自身的情况下构成的。以下为经典的递归阶乘函数。
function factorial(n){ if(n <=1 ){ return 1; }else{ return n * factorial(n-1); } }
这个函数看起来没什么问题,但是以下代码却会导致其出错。
var anotherFactorial = factorial; factorial = null; alert(anotherFactorial(4)) //报错
因为,原本把factorial()函数保存在变量anotherFactorial中,后又将factorial赋值为null,指向原始函数的引用只剩下一个。调用anotherFactorial()时,由于必须执行factorial(),而factorial已经不再是函数,所以会报错。这种情况下,使用arguments.callee可以解决。
arguments.callee是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用。
var factorial = (function f(n){ if(n <=1 ){ return 1; }else{ return n * arguments.callee(n-1); } })
使用arguments.callee代替函数名,可以确保无论怎样调用函数都不会出现问题。在编写递归函数时,使用arguments.callee总比使用函数名更保险。
在严格模式下,ES5禁止使用arguments.callee(),不能通过脚本访问arguments.callee,访问这个属性会导致错误。当一个函数必须调用自身的时候,避免使用,要么给函数表达式一个名字,要么使用一个函数声明。
var factorial = (function f(n){
if(n <=1 ){
return 1;
}else{
return n * f(n-1);
}
})
创建了一个名为f()的命名函数表达式,然后将它赋值给变量factorial。即便把函数赋值给了另一个变量,函数的名字 f 仍然有效,递归照样正确完成,这种方式在严格模式和非严格模式下都行得通。