闭包是函数与其定义时词法环境的组合,由javascript运行时自然形成;关键在于函数定义即锁定可访问变量范围(词法作用域),外层函数执行完毕后,只要内部函数被外部持有,其变量对象便通过作用域链持续驻留内存。

闭包不是写出来的技巧,而是 JavaScript 运行时自然形成的结果:一个函数带着它定义时所在的作用域一起“活下来”,就构成了闭包。关键不在语法形式,而在执行上下文如何保留、作用域链如何持续有效。
闭包由函数 + 词法环境共同构成
函数在定义那一刻,就锁定了它能访问的变量范围——这叫词法作用域。这个范围不是靠调用位置决定的,而是看代码写在哪一层嵌套里。比如:
- 函数内部引用了外层函数的变量(如参数或局部变量)
- 这个内部函数被返回、赋值给变量、传作回调,即被外部持有
- 外层函数执行结束,但它的变量对象没被回收——因为作用域链还在被内部函数引用
作用域链是闭包存活的唯一路径
闭包不复制变量,也不快照值,而是通过真实的作用域链实时查找。每次调用闭包函数,引擎都沿着这条链向上找变量:
- 链的第一级是闭包自身的活动对象(通常为空)
- 第二级是外层函数执行时生成的变量对象(含 x、y 等)
- 再往上是更外层作用域,直到全局对象
- 如果变量是对象,所有共享该闭包的调用访问的是同一个引用
变量生命周期由引用关系决定
外层函数执行完,本该销毁其执行上下文。但只要闭包还存在且被引用,JS 引擎就必须保留对应的作用域链和变量对象:
- 没有返回内部函数 → 外层变量随上下文销毁,不形成闭包
- 返回并被外部变量持有(如 const add5 = makeAdder(5))→ 变量 x 驻留内存
- 当闭包引用被清除(如 add5 = null),且无其他引用,变量才可能被垃圾回收
闭包不是动态绑定,而是静态词法 + 运行时驻留
常说的“动态”容易误导。准确说是:
- 作用域关系静态确定:函数写在哪,就能访问哪些外层变量,跟怎么调用无关
- 变量是否驻留动态决定:取决于有没有活跃的闭包引用它
- 这种组合让闭包既能保持语义一致性,又能灵活维持状态











