阶乘 n! 有多种实现方式,既可以使用递归,也可以使用迭代、记忆化、闭包、尾递归、甚至异步方式。下面是 常见的7种实现方式(含思路):
✅ 1. 普通递归(经典写法)
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
- 优点:代码简洁
- 缺点:大数爆栈(Maximum call stack size exceeded)
✅ 2. 尾递归
📌 尾递归特点:
- 最后一行是 return 调用自身;
- 没有多余的计算、回溯栈;
- 参数
acc(accumulator)是累积结果。
function factorial(n, acc = 1) {
if (n <= 1) return acc;
return factorial(n - 1, n * acc);
}
- 优点:理论上可以优化栈空间
- 缺点:JavaScript 大多数环境不支持尾调用优化
✅ 3. 迭代 / 循环实现
function factorial(n) {
let res = 1;
for (let i = 2; i <= n; i++) {
res *= i;
}
return res;
}
- 优点:效率高、不爆栈
- 缺点:结构不如递归清晰
✅ 4. 记忆化递归(Memoization)
const cache = {};
function factorial(n) {
if (n <= 1) return 1;
if (cache[n]) return cache[n];
return cache[n] = n * factorial(n - 1);
}
- 优点:避免重复计算
- 缺点:空间换时间,递归仍可能爆栈
✅ 5. 闭包版(记忆化 + 闭包封装)
const factorial = (() => {
const cache = {};
return function f(n) {
if (n <= 1) return 1;
if (cache[n]) return cache[n];
return cache[n] = n * f(n - 1);
}
})();
- 优点:数据私有化、封装性强
- 缺点:递归栈依然存在问题
✅ 6. BigInt 支持的大数阶乘
function factorial(n) {
let res = 1n;
for (let i = 2n; i <= BigInt(n); i++) {
res *= i;
}
return res;
}
- 优点:支持计算超大阶乘(如 10000!)
- 缺点:结果是
BigInt,不适用于浮点运算场景
✅ 7. 异步递归(用于学习 async/await)
async function factorial(n) {
if (n <= 1) return 1;
const prev = await factorial(n - 1);
return n * prev;
}
- 优点:理论上可避免同步爆栈(但没实质优化)
- 缺点:性能低、无实际意义,更多用于 async 控制流学习
🚀 你可以根据用途选择不同实现:
| 场景 | 推荐写法 |
|---|---|
| 小数计算 | 普通递归 / 迭代 |
| 大数计算 | BigInt 迭代 |
| 面试优化 | 尾递归 / 记忆化递归 |
| 数据封装 | 闭包记忆化 |