闭包的本质是内部函数对定义时外部作用域变量的持续访问权,源于词法作用域和作用域链的保留;它不是语法糖,而是函数嵌套、引用外层变量、内层函数外移三个条件满足时的自然结果。

闭包的本质,是内部函数对定义时外部作用域中变量的**持续访问权**,这种权限不依赖于外部函数是否还在执行,而源于 JavaScript 的词法作用域机制和作用域链的保留。
词法作用域决定“谁可以访问谁”
变量能否被访问,取决于它在代码中声明的位置,而不是运行时调用的位置。只要一个函数在书写时处于某个外部作用域内部,它就天然拥有对该作用域中变量(包括参数、let/const/var 声明的局部变量)的读写能力。
- 这个“位置关系”在函数定义时就固定了,运行时不会改变
- 哪怕外部函数已执行完毕、其执行上下文被销毁,该访问权依然存在
- 引擎通过保存函数创建时的词法环境(LexicalEnvironment),维持这条通路
作用域链是访问权的实现路径
每次函数执行时,JavaScript 引擎会构建一条作用域链:从当前函数自身的词法环境开始,逐级向上查找父级词法环境,直到全局环境。闭包之所以能访问外部变量,正是因为这条链没有在外部函数退出后被切断。
- 内部函数持有着对外部词法环境的引用,不是拷贝值,而是引用地址
- 因此变量值是实时的——修改它,下次访问就是新值(如计数器例子中的 count)
- 这也意味着这些变量不会被垃圾回收,只要闭包还存在
访问权 ≠ 调用权,也不等于暴露权
闭包赋予的是“内部函数访问外部变量”的能力,但并不自动让这些变量对外可读或可改。是否暴露,取决于你如何设计返回的接口。
- 只返回一个读取函数 → 外部只能看,不能改(只读封装)
- 返回多个方法(如 increment 和 current)→ 控制性暴露行为,隐藏状态
- 不返回任何东西,只在内部使用 → 变量彻底私有,连调用者都无感知
这不是语法糖,而是作用域规则的自然结果
闭包不是 JavaScript 特意加的功能开关,而是当满足三个条件时,语言底层机制必然产生的现象:
- 函数嵌套(内层函数写在外层函数体内)
- 内层函数引用了外层函数的变量(形成自由变量)
- 内层函数被带到外层作用域之外(比如 return 出去、赋给全局变量、传给 setTimeout 等)











