递归是在一个函数调用自身的情况下构成的

下面是一个经典的递归阶乘函数

1
2
3
4
5
6
function factorial(num){
	if(num < 1)
		return 1;
	else
		return num * factorial(num -1);
}

上面的写法受制于函数名。将factorial置空之后将会出错

1
2
3
4
5
6
7
8
9
10
11
function factorial(num){
	if(num < 1)
		return 1;
	else
		return num * factorial(num -1);
}
var anotherFactorial = factorial;
factorial = null;
//console.log(anotherFactorial(4));
//出错,因为在执行return num * factorial(num -1); 时factorial已经不再是函数,为 null。

使用arguments.callee可以解决这个问题。arguments.callee是指向正在执行的函数的指针,因此可用来实现对函数的递归调用。 例如:

1
2
3
4
5
6
7
8
9
10
function factorial(num){
	if(num < 1)
		return 1;
	else
		return num * arguments.callee(num -1);
}

var anotherFactorial = factorial;
factorial = null;
console.log(anotherFactorial(4));	//24

编写递归时,通过使用arguments.callee代替函数名,比使用函数名更保险。

但在严格模式下,不能访问arguments.callee,访问这个属性会导致错误。因此可以使用命名函数表达式来达成相同的效果。例如:

1
2
3
4
5
6
7
8
9
10
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

以上代码创建了一个名为f( )的命名函数,然后将它赋值给变量factorial。即便把函数赋值给另一个变量,函数的名字f仍然有效,所以递归调用能够正确完成。这种方式在严格模式和非严格模式都是允许的。

【本文内容摘自:《JavaScript高级程序设计》(第3版)Nicholas C.Zakas 著 李松峰 曹力 译】