递归是一种常见的编程技巧, 实名递归相信大家都不陌生, 但如果想要实现匿名递归呢? 比如想要返回一个匿名递归函数, 又或者是定义一个匿名递归函数并直接调用它, 该怎样去做呢? 本文将来探讨一下它的实现.
实名递归
我们还是先从实名递归说起吧, 还是用那个最简单的求阶乘的例子:
function fact(n) {
if (n < 2) {
return n;
} else {
return n * fact(n - 1);
}
}
console.log(fact(5));
递归要求自己调用自己, 如果函数有名字, 这就太简单不过了.
利用变量实现递归
函数还可以赋给一个变量, 不过要实现递归, 函数体里面还是要依赖这个变量名:
var f = function(n) {
if (n < 2) {
return n;
} else {
return n * f(n - 1);
}
}
console.log(f(5));
应该说这种方式跟之前的其实没有本质的不同.
匿名递归
现在我们来探讨匿名递归的实现.
初步设想
如果想要返回一个匿名递归函数, 又或者是定义一个匿名递归函数并直接调用它:
(function (n) {
if (n < 2) {
return n;
} else {
return n * ?(n - 1);
}
})(5);
如果没有一个名字, 代码中那个问号我们就不知道要填写什么, 就没法形成递归了, 此时我们要怎么办呢? 这时就要请出 arguments
对象了.
arguments 对象
在 javascript 的函数中, arguments
对象代表了实际调用时的参数对象. 在我们的递归函数中, 实际上我们也可以完全不用去定义 "形式参数" n:
function factNoParam() {
if (arguments[0] < 2) {
return arguments[0];
} else {
return arguments[0] * factNoParam(arguments[0] - 1);
}
}
console.log(factNoParam(5));
只要我们在调用时传入了实际的参数, 就可以用 arguments[0]
取得实际传入的这个参数的值.
如果有更多的参数, 还可以
arguments[1]
,arguments[2]
等来取得.
arguments.callee 属性
arguments
可以用来获取参数, 相信你可能已经知道了, 但 arguments
对象其实还有一个属性, 即所谓的 callee
. arguments.callee
代表了这个函数本身. 这是什么意思呢? 其实我们完全可以把 fact
写成这样:
function fact(n) {
if (n < 2) {
return n;
} else {
return n * arguments.callee(n - 1);
}
}
console.log(fact(5));
那么它依然是递归的. 因为 arguments.callee
实际就等于 fact
.
那么, 到了这里, 有了这个属性的帮助, 要实现匿名递归就不难了, 只要把 ? 改为 arguments.callee
即可:
(function (n) {
if (n < 2) {
return n;
} else {
return n * arguments.callee(n - 1);
}
})(5);
如果有需要, 也可以把它作为匿名递归返回.
关于 javascript 实现匿名递归的介绍就到这里.