js引擎实现闭包的核心是词法环境绑定与作用域链持久化:函数创建时静态绑定[[environment]]指向定义处的词法环境,内部函数共享外部变量内存地址而非复制值,变量因被引用而延迟回收,作用域链按嵌套层级逐级查找,闭包本质是函数与其捕获的词法环境的运行时组合。

JS 引擎实现闭包作用域,核心在于词法环境绑定和作用域链持久化,不是靠“复制变量”,而是让内部函数携带对原始词法环境的引用。
词法环境在函数创建时就被锁定
函数定义那一刻,引擎就为其生成一个隐藏的 [[Environment]](或 V8 中的 [[Scopes]]),指向它所在位置的词法作用域。这个绑定是静态的、不可更改的——和函数在哪被调用无关。
- 比如
function inner() { return a; }写在outer()里,那它的 [[Environment]] 就直接指向outer的词法环境 - 即使
inner被返回到全局并执行,查找a时仍会顺着这条链往上找,而不是重新去outer执行时的作用域里“翻记录”
变量不销毁,是因为被引用着
正常情况下,outer() 执行完,它的执行上下文(包括局部变量)会被垃圾回收器释放。但一旦 inner 持有对 a 的引用,JS 引擎就会判定:这个变量还在被活的函数使用,不能回收。
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
- 不是把
a的值拷一份给inner,而是让inner和outer共享同一块内存地址 - 所以多次调用
counter()返回的函数,每次修改的都是同一个count变量
作用域链是一条可追溯的链接结构
每个函数执行时,引擎会构建一条作用域链:从当前函数的活动对象开始,依次链接外层词法环境,最终到全局对象。闭包让这条链在外部函数退出后依然有效。
- 链上每一环都保存着变量对象(Variable Object)或词法环境记录(Lexical Environment Record)
- 变量查找严格按链顺序:当前作用域 → 外层作用域 → … → 全局,中途找到即停
- 这种链式结构由引擎底层维护,开发者无法直接访问,但可通过
console.dir(fn)在某些环境中观察[[Scopes]]
闭包本质是函数与词法环境的组合体
所谓“闭包”,不是一个新对象类型,而是函数实例 + 它定义时捕获的词法环境构成的一个运行时实体。引擎不会单独标记“这是闭包”,而是在函数调用时,自动启用它绑定的完整作用域链。
- 同一个函数在不同位置定义,会形成不同的闭包(因为 [[Environment]] 指向不同)
- 哪怕函数体完全一样,只要定义位置不同,闭包行为就可能不同
- 这也是为什么
for (var i = 0; i console.log(i), 0); }输出三个 3 —— 所有回调共享同一个i的引用,而那个i属于函数级作用域










