You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript递归调试解惑:阶乘函数多余1输出疑问

递归阶乘代码的执行流程解析

首先先看你提供的这段递归代码:

function fact(n){ 
  if(n ==1){ 
    return 1 
  } else{ 
    console.log(fact(n-1)) 
    return n*fact(n-1) 
  } 
}

你困惑的点在于,为什么除了最底层if(n==1)返回的那个1,控制台还会打印出其他的1?其实核心原因很简单——这段代码在else分支里重复调用了两次fact(n-1),这两次调用是完全独立的,都会触发完整的递归流程,导致底层的fact(1)被多次执行,每次执行都会返回1,当上层的console.log捕获到这个返回值时,就会打印出来。

让我们用具体的调用例子一步步拆解:

例子1:调用fact(2)的完整流程

  • 调用fact(2),n不等于1,进入else分支
  • 首先执行console.log(fact(1)):
    • 触发fact(1)的调用,n=1满足条件,直接返回1
    • 控制台打印第一个1
  • 接着执行return 2 * fact(1):
    • 又一次触发fact(1)的调用,再次返回1
    • 计算得到2*1=2,作为fact(2)的返回值

例子2:调用fact(3)的完整流程

  • 调用fact(3),n不等于1,进入else分支
  • 先执行console.log(fact(2)):
    • 进入fact(2)的执行流程:
      • 先调用fact(1),控制台打印第一个1
      • 再调用fact(1),返回2
    • 控制台接着打印2
  • 然后执行return 3 * fact(2):
    • 再次进入fact(2)的执行流程:
      • 又一次调用fact(1),控制台打印第二个1
      • 再调用fact(1),返回2
    • 计算得到3*2=6,作为fact(3)的返回值

所以调用fact(3)时,你会在控制台看到先打印1,再打印2,最后又打印一个1——这就是那些额外1的来源。

如果要解决这个冗余调用的问题,你可以把递归的结果存到一个变量里复用,避免重复触发递归:

function fact(n){ 
  if(n ==1){ 
    return 1 
  } else{ 
    const prevFact = fact(n-1)
    console.log(prevFact) 
    return n*prevFact 
  } 
}

这样每次递归只会调用一次fact(n-1),打印的内容也会更符合预期,比如调用fact(3)会依次打印1、2,最终返回6。

内容的提问来源于stack exchange,提问作者siddharth shah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:39:37