词法环境(Lexical Environment)与作用域(Scope)在 JavaScript 中是紧密关联的概念,其关系可总结为以下核心要点:


一、词法环境与作用域的定义

  1. 词法环境
    • 词法环境是 JavaScript 引擎在编译阶段创建的静态数据结构用于存储变量、函数声明及对外部词法环境的引用。它由两部分组成:
      • 环境记录(Environment Record):存储当前作用域内的变量、函数声明等。
      • 外部词法环境引用outer):指向父级词法环境,形成作用域链。
    • 词法环境是 ES5 规范中对“作用域”的标准化术语,两者本质相同。
  2. 作用域
    • 作用域是变量和函数的可访问范围规则,由词法环境的静态结构决定。例如,函数内部的变量仅在函数作用域内有效。

二、词法环境与作用域的等价性

  1. 词法环境 = 作用域
    • 在 ES5 及更高版本中,词法环境直接等同于作用域。例如,函数定义时创建的词法环境即为其作用域,变量查找通过作用域链实现。
  2. 作用域链的实现
    • 词法环境通过 外部引用(Outer) 连接成链式结构。当变量无法在当前词法环境中找到时,引擎会逐层向上查找父级词法环境,直到全局环境或 null(全局环境的 Outernull)。

三、词法环境的分类与作用

  1. 变量环境与词法环境
    • 变量环境(Variable Environment):在编译阶段创建,用于处理 var 变量和函数声明的提升。
    • 词法环境(Lexical Environment):在执行阶段激活,用于处理 letconst 等块级作用域变量。
    • 两者在函数调用时合并为 活动对象(Activation Object),即变量对象(Variable Object)。
  2. 环境记录的细分
    • 声明式环境记录(Declarative Environment Record):存储 letconst、函数声明等。
    • 对象式环境记录(Object Environment Record):存储 var 变量和全局对象的属性。

四、词法作用域的实现原理

  1. 静态绑定
    • 词法作用域的绑定在代码定义时确定,与函数调用位置无关。例如,闭包中的函数保留定义时的词法环境引用。
  2. 块级作用域的实现
    • letconst 通过词法环境在执行阶段动态创建块级作用域,避免了 var 的变量提升问题。例如:
      { let a = 1; }  // a 仅在代码块内有效

五、词法环境与闭包的关系

  1. 闭包的本质
    • 闭包是函数与词法环境的组合,函数保留对定义时词法环境的引用。例如:
      function outer() {
        let count = 0;
        return function inner() { count++; }; // inner 保留对 outer 词法环境的引用
      }
  2. 变量查找规则
    • 闭包中的变量查找遵循作用域链规则,从当前词法环境开始向外层环境查找。

六、总结

概念词法环境作用域
定义存储变量和外部引用的静态结构变量和函数的可访问范围规则
实现通过环境记录和外部引用形成作用域链由词法环境的静态结构决定
动态性静态绑定,编译阶段确定由代码结构决定,运行时不可变
与闭包关系闭包的核心是函数与词法环境的绑定闭包通过作用域链访问外层变量
通过词法环境与作用域的绑定机制,JavaScript 实现了静态作用域和闭包功能,确保了代码的可预测性和模块化设计。