尾调用优化(Tail Call Optimization)
尾调用优化可以避免栈溢出,但并非所有引擎都实现。
📚 基本概念
什么是尾调用
尾调用是函数最后一步调用另一个函数:
// ✅ 尾调用
function f(x) {
return g(x); // 最后一步调用
}
// ❌ 不是尾调用
function f(x) {
return g(x) + 1; // 调用后还有操作
}🎯 尾递归
普通递归
// ❌ 普通递归:可能栈溢出
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1); // 不是尾调用
}
factorial(10000); // 可能栈溢出尾递归
// ✅ 尾递归:可以优化
function factorial(n, acc = 1) {
if (n <= 1) return acc;
return factorial(n - 1, n * acc); // 尾调用
}
factorial(10000); // 理论上可以优化⚠️ 浏览器支持
当前状态
- Safari:支持尾调用优化
- Chrome/Edge:不支持
- Firefox:不支持
检查支持
function testTailCall() {
'use strict';
function f(n) {
if (n === 0) return true;
return f(n - 1);
}
try {
f(100000);
return true; // 支持尾调用优化
} catch (e) {
return false; // 不支持
}
}💡 替代方案
1. 使用循环
// 将递归改为循环
function factorial(n) {
let result = 1;
for (let i = 2; i <= n; i++) {
result *= i;
}
return result;
}2. 使用蹦床函数(Trampoline)
function trampoline(fn) {
while (typeof fn === 'function') {
fn = fn();
}
return fn;
}
function factorial(n, acc = 1) {
if (n <= 1) return acc;
return () => factorial(n - 1, n * acc);
}
const result = trampoline(() => factorial(10000));🔗 相关链接
参考: