作用域与闭包

作用域决定变量在何处可见、可访问;闭包是“函数 + 其创建时的词法环境”的组合,使内层函数能持续访问外层变量。


词法作用域(Lexical scope)

函数定义时书写位置决定它能访问哪些外层变量,而非调用位置。这与 函数this 的绑定规则不同:this 多由调用方式决定,词法作用域由代码结构决定。


var 与「函数作用域」「变量提升」

  • var:函数作用域,或在全局成为全局对象属性(浏览器模式下)。
  • 提升(hoisting):声明会被拿到所在作用域顶部“注册”,赋值不提升,故易出现 undefined 的暂时表现。
  • 现代代码中优先 let / const(见 ES6+)。

块级作用域:let / const

  • :一对 {}iffor、独立块等)。
  • let:可重新赋值;const:绑定不可重新赋值(对象本身仍可变,除非 Object.freeze 等)。
  • 不得重复声明同一标识符于同一块内。

暂时性死区(TDZ)

块内 let / const 声明之前的区间,访问该标识符会 ReferenceError。这避免了 var 在块顶“静默 undefined”的部分问题。


闭包(Closure)

function outer(x) {
  return function inner(y) {
    return x + y // inner「闭合」了 outer 的词法环境中的 x
  }
}
const f = outer(1)
f(2) // 3

常见用途:工厂函数、防抖节流(见 性能优化)、模块化 模式中的私有状态、事件回调中记住配置等。

注意:闭包会持有对外层变量的引用,配合 DOM 或定时器时若不及时解除引用,可能造成内存无法回收(见 性能优化)。


相关链接

  • 函数(箭头函数与 this、高阶函数)
  • ES6+let / const、块级作用域)
  • 原型与继承(与对象方法中的 this 配合理解)
  • 性能优化(闭包与内存、事件解绑)
  • 模块化(IIFE、词法作用域与模块私用变量)