函数式编程有一个概念,叫做柯里化(currying),意思是将多参数的函数转换成单参数的形式。这里也可以使用柯里化。
\
function currying(fn, n) {
return function (m) {
return fn.call(this, m, n);
};
}
\
function tailFactorial(n, total) {
if (n === 1) return total;
return tailFactorial(n - 1, n * total);
}
\
const factorial = currying(tailFactorial, 1);
\
factorial(5) // 120
上面代码通过柯里化,将尾递归函数tailFactorial变为只接受一个参数的factorial。
\
第二种方法就简单多了,就是采用 ES6 的函数默认值。
\
function factorial(n, total = 1) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
\
factorial(5) // 120
上面代码中,参数total有默认值1,所以调用时不用提供这个值。
\
总结一下,递归本质上是一种循环操作。纯粹的函数式编程语言没有循环操作命令,所有的循环都用递归实现,这就是为什么尾递归对这些语言极其重要。对于其他支持“尾调用优化”的语言(比如 Lua,ES6),只需要知道循环可以用递归代替,而一旦使用递归,就最好使用尾递归。