闭包的本质是函数与其定义时词法环境的绑定,属运行时现象而非语法结构;需同时满足三条件:存在嵌套函数、内层函数被带出外层作用域、内层函数实际访问外层局部变量。

闭包的本质,是函数与其定义时所处的词法环境(Lexical Environment)的绑定;它不是语法结构,而是一种运行时现象——只要函数在定义位置能访问某个外部变量,且该函数后续在外部被调用并实际使用了那个变量,就形成了闭包。
闭包的三个硬性条件
缺一不可:
- 存在嵌套函数:内层函数必须写在外层函数内部
- 内层函数被“带出”外层作用域:比如作为返回值、赋给全局变量、传入 setTimeout 或事件监听器等
- 内层函数真正读取或修改了外层函数的局部变量(不是参数、也不是全局变量)
词法作用域决定“谁可见”,而非“谁在调用”
JS 的作用域是静态的,由代码书写结构决定。函数在哪写的,就固定绑定了哪一层的变量环境。哪怕把它传到另一个文件、另一个模块、甚至另一个事件循环阶段执行,它依然按原样向上查找变量。
例如:
const add5 = makeAdder(5);
setTimeout(add5, 100, 3); // 输出 8 —— x=5 仍可访问,不因 makeAdder 执行完而丢失
闭包不是快照,而是活引用
很多人误以为闭包“复制”了变量值,其实不然。它持有一个对原始变量的实时引用:
- 多个闭包共享同一份外层变量,一个改,其他立刻可见
- 变量不会被垃圾回收,因为闭包通过 [[Environment]] 持有对其词法环境的强引用
- V8 引擎会把这类变量从栈迁移至堆,确保生命周期与闭包一致
作用域链是闭包生效的底层路径
每次变量访问,引擎都沿着作用域链逐级查找。这条链在函数创建时就固化在 [[Environment]] 中,是一条指向外层词法环境的单向链表:
- 起点:当前函数自己的词法环境
- 中间节点:所有外层嵌套函数的词法环境(按定义层级依次向上)
- 终点:全局环境
闭包之所以有效,正是因为这条链没有断裂——即使外层函数执行上下文早已销毁,链上的节点仍被内层函数牢牢持有。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











