蹦床函数通过将递归调用转为返回thunk(延迟执行的函数)来避免栈溢出,由蹦床器循环执行thunk直至返回非函数值,调用顺序由thunk返回时机和类型显式控制。

蹦床函数本身不直接控制递归调用的顺序,而是把递归调用“展开”成一个循环执行的步骤序列,从而避免栈溢出,并让调用顺序由你显式决定。
把递归调用转为返回函数的链式结构
传统递归是函数直接调用自身,每次调用压栈;蹦床函数要求每个“递归步骤”不直接调用,而是返回一个函数(thunk),这个函数封装了下一步要做的计算。蹦床器(trampoline)负责逐个执行这些函数,直到返回非函数值为止。
- 每次“递归”不是
factorial(n-1),而是() => factorial(n-1) - 主函数只负责构造和返回 thunk,不执行它
- 蹦床器在一个 while 循环里反复调用当前 thunk,用其返回值决定是否继续
顺序控制靠返回值类型和执行时机
蹦床器通过判断每次返回值的类型来决定流程:如果返回的是函数,就立刻调用它;否则就结束并返回该值。这意味着“调用顺序”完全由你返回哪个 thunk、何时返回、是否嵌套决定。
- 想先算左子树再右子树?就先返回左子树的 thunk,等它彻底完成再返回右子树的 thunk
- 想交错执行(如遍历+处理)?可以在一个 thunk 里先做部分工作,再返回下一个阶段的 thunk
- 想中途终止?直接返回结果值,蹦床器就会跳出循环
实际写法示例:尾递归阶乘的蹦床实现
普通尾递归:
function fact(n, acc = 1) {<br> return n }蹦床版:
function factTramp(n, acc = 1) {<br> if (n return () => factTramp(n - 1, n * acc);<br>}<br><br>function trampoline(fn, ...args) {<br> let result = fn(...args);<br> while (typeof result === 'function') {<br> result = result();<br> }<br> return result;<br>}这里顺序完全由 factTramp 的返回逻辑控制:只有当前步完成,才生成下一步;没有隐式调用栈,也没有并发或乱序风险。
注意边界:不是所有递归都适合直接蹦床化
非尾递归(比如二叉树中序遍历)需要手动拆解为多个状态阶段,把“等待左子树返回后再处理根节点”这种依赖关系,编码为连续的 thunk 返回链。
- 需显式维护上下文(如当前节点、待执行动作、已缓存数据)
- 可借助对象或闭包保存中间状态,每个 thunk 负责推进一个状态
- 顺序控制力变强了,但代码复杂度也相应上升











