蹦床函数通过显式提取调用栈中的隐式状态并封装为函数对象(thunk)实现非阻塞递归,每次返回的thunk携带参数和中间结果作为闭包或绑定参数,由trampoline循环执行,仅维持两个栈帧,彻底规避栈溢出。

蹦床函数不是靠“隐藏状态”工作,而是把原本藏在调用栈里的隐式状态,显式地拎出来,存进函数对象里——关键在于:它不依赖栈帧维持上下文,而是靠返回的函数(thunk)携带参数和中间结果。
函数对象作为状态容器
每次递归本该压栈的变量(比如累加值、剩余步数、当前节点),不再靠栈帧自动保存,而是作为闭包变量或绑定参数,固化在返回的函数对象中。
- 例如
sum(x, y)改写为return () => sum(x + 1, y - 1),x + 1和y - 1就被捕获进新函数的闭包,成为它的私有状态 - 用
bind绑定参数(如sum.bind(null, x + 1, y - 1))效果相同:参数被固化进函数对象内部,调用时无需额外传入 - 这个函数对象本身就是一个轻量级状态快照,不含执行逻辑,只含数据和下一步动作
状态流转靠“返回-执行”循环驱动
蹦床函数(trampoline)本身不保存状态,它只是个执行引擎:拿到一个函数对象 → 执行它 → 拿到返回值 → 判断是否仍是函数 → 是就继续,不是就结束。
- 状态不堆在栈上,而是在每次迭代中“移交”给下一个函数对象
- 整个过程只有两个栈帧:trampoline 的 while 循环帧 + 当前 thunk 的调用帧(执行完即释放)
- 没有全局变量、没有 mutable 对象,状态完全由函数对象的闭包或绑定参数承载
支持复杂状态:闭包 + 参数组合
实际应用中,状态往往不止一两个数。可通过闭包捕获结构体,或把多个值打包成单个参数对象:
- 闭包方式:函数内定义临时对象,再返回捕获它的 thunk
- 参数对象方式:用
{ acc: x, remaining: y, context: obj }作为唯一参数,保持函数签名统一 - 注意避免在 thunk 中引用外部可变对象——否则状态会意外共享或污染
与委托/桩函数(Trampoline Stub)的区别
C++ 中的“蹦床”(如 StaticDelegate)也叫 trampoline,但它作用不同:它不处理递归,而是解决类型擦除后的调用转发——把通用 void* 数据 + 固定签名函数指针,还原成原始类型的调用。这里的“状态”是对象地址和类型信息,存在固定大小缓冲区里,靠静态模板函数解包执行。
- JS/Python 蹦床:状态 = 递归参数 + 中间结果,存在闭包或绑定中
- C++ 委托蹦床:状态 = this 指针或 lambda 捕获体,存在 32 字节栈缓冲中
- 两者共性:都把“怎么调”和“调什么”分离,让执行逻辑外置、状态内聚

















