闭包是函数与其定义时词法环境的绑定,本质为“函数+词法环境”不可分割的整体;它依赖词法作用域和函数作为一等值共同实现,变量为真实引用而非拷贝,且不随外层执行上下文销毁而释放。

闭包不是 JavaScript 特有的“语法糖”,而是词法作用域(Lexical Scope)与函数作为一等值(First-class Function)共同作用下的自然语义结果。
闭包本质是“函数 + 词法环境”的绑定
当一个函数在其定义位置捕获了外层作用域中的变量(即自由变量),这个函数就和它定义时的词法环境构成了一个不可分割的整体——这就是闭包。所谓“词法环境”,指的就是函数声明时所在的作用域链快照,包括所有父级作用域中可访问的变量绑定。
- 函数在哪里被调用不重要,关键是在哪里被定义
- 即使外层函数已执行完毕、其执行上下文被销毁,只要内层函数还存在且被引用,引擎就会保留该词法环境中的变量
- 闭包中的变量不是拷贝,而是真实引用;修改它会影响后续所有对该闭包的调用
作用域模型如何支撑闭包语义
JavaScript 使用静态(词法)作用域规则:变量的可访问性由代码书写结构决定,而非运行时调用栈。这使得“函数记住自己诞生的位置”成为可能。
- 每个函数对象内部都隐式关联着 [[Environment]] 内部槽,指向其创建时的词法环境
- 引擎在执行函数时,会沿 [[Environment]] 链向上查找标识符,从而实现对外部变量的持续访问
- 这种查找机制不依赖于调用路径,所以即使把闭包传到另一个模块、另一个事件回调里,它依然能正确读写原始变量
闭包不是“意外产物”,而是作用域设计的必然体现
没有词法作用域,就没有确定的变量可见范围;没有函数作为返回值的能力,就无法将内层函数带出原作用域。两者缺一不可。
- 动态作用域语言(如早期 Lisp 变体)中,函数访问的是调用时的环境,无法形成稳定闭包
- 若函数不能作为值传递或返回,即便有词法作用域,也无法让内层函数“逃逸”并长期持有外部变量
- 因此,“闭包语义”是作用域模型 + 函数地位共同定义的语言契约,不是可选特性,而是底层行为逻辑
不复杂但容易忽略











