/**
* 递归:递归函数是一个函数通过名字调用自身的情况下构成的
*/
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * factorial(num - 1);
}
}
/**
* 这是一个经典的递归阶乘函数。虽然看起来没有问题,但下面这种情况可能会导致出错。
*/
var anotherFactorial = factorial;
factorial = null;
console.log(factorial(5)); // 报错! TypeError: factorial is not a function
/**
* 以上代码先把 factorial 函数保存在变量 anotherFactorial 中,然后将 factorial 变量设置为 null,结果指向原始函数的引用只剩下一个。
* 但是接下来调用 anotherFactorial 时由于内部调用了 factorial,而此刻 factorial 已经不是函数了,所以会导致错误。
* 这种情况下可以用 arguments.callee 解决这个问题。
* arguments.callee 是一个指向正在执行的函数的指针,可以用它来实现对函数的递归调用。
* 通过使用 arguments.callee 代替函数名,可以确保无论怎样调用函数都不会报错,所以编写递归函数时使用它更为保险。
*/
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1);
}
}
/**
* 但在严格模式下,不能通过脚本访问 arguments.callee,访问这个属性会导致错误。
* 不过可以使用函数表达式来达到相同的结果。
* 首先创建一个名为 f 的命名函数表达式,让后将它赋值给变量 factorial。
* 即便把函数赋值给另一个变量,函数的名字 f 仍然有效,所以递归调用能正确完成。
* 这种方式在严格模式和非严格模式都行的通。
*/
var factorial = (function f(num) {
if (num <= 1) {
return 1;
} else {
return num * f(num - 1);
}
})
var anotherFactorial = factorial;
factorial = null;
console.log(anotherFactorial(5)); // 120 此时就不会报错