函数表达式实现递归的关键是让函数能引用自身,常用方式是赋值给变量后通过变量名调用,或使用命名函数表达式(如function fact(n){...})确保内部可递归且不影响外部作用域。

函数表达式实现递归调用的关键在于:**必须让函数能引用自身**,而匿名函数表达式本身没有名字,所以不能直接用函数名调用自己。解决办法是借助变量名、arguments.callee(已废弃)、命名函数表达式,或更现代的方案如箭头函数配合变量赋值+显式命名。
用变量名间接引用自身
最常用也最清晰的方式:把函数表达式赋值给一个变量,函数体内通过该变量名调用自己。
注意变量必须在函数执行前已声明并赋值,且不能用 const 声明后重新赋值(但可正常使用)。
- ✅ 推荐写法(使用
let或const):
const factorial = function(n) {
if (n
- ⚠️ 避免用
var+ 重赋值,容易出错:
var fn = function(n) { return n > 1 ? n * fn(n-1) : 1; };
fn = null; // 此时再调用会报错:Cannot read property '...' of null
使用命名函数表达式(Named Function Expression)
给函数表达式起一个内部名称,这个名称只在函数体内可见,不影响外部作用域,且不受变量是否被重新赋值的影响。
- 函数名仅在函数内部可用,可用于递归,也利于调试(堆栈中显示函数名);
- 即使外部变量被覆盖,递归仍正常工作。
const factorial = function fact(n) {
if (n "boom"; // 外部变量变了,不影响内部 fact 调用
console.log(factorial(4)); // 24,依然正确
避免使用 arguments.callee
过去曾用 arguments.callee 指向当前正在执行的函数,从而实现匿名递归:
const factorial = function(n) {
if (n <p><strong>不建议使用</strong>:它在严格模式下抛错,影响性能,且破坏内联优化,已被现代 JavaScript 规范视为遗留特性。</p><h3>箭头函数 + 显式命名变量(需注意 this 和 arguments)</h3><p>箭头函数没有自己的 <code>this</code> 和 <code>arguments</code>,也不能用 <code>arguments.callee</code>,所以必须依赖外部变量名递归:</p>
- 可以正常使用,但要注意:它不能替代传统函数表达式在需要
this或arguments的场景; - 递归逻辑和普通函数表达式一致,靠变量名引用。
const factorial = (n) => n <p>只要变量名没被改写,这种写法简洁有效。但若需访问调用时的 <code>arguments</code> 或动态 <code>this</code>,就得换回普通函数表达式。</p>











