词法环境是JavaScript中静态确定的作用域实现机制,由环境记录和指向外层的outer引用组成,其outer链依据函数定义位置而非调用位置绑定。

作用域的本质,就是 JavaScript 引擎查找变量时所依赖的一套“位置规则”,而词法环境(Lexical Environment)是这套规则背后的具体实现机制——它在代码写完(即“词法”阶段)就已静态确定,不是运行时才决定的。
词法环境是什么:一个带记录和链接的盒子
每个执行上下文(比如函数调用、全局代码)都会创建一个词法环境。它由两部分组成:
- 环境记录(Environment Record):真实存储变量、函数声明的地方,像一张本地“小账本”;
- 外部词法环境引用(outer):指向其外层作用域的词法环境,形成一条可向上追溯的链(即词法环境链)。
这个“outer”链接不是靠运行时调用关系决定的,而是根据函数在源码中定义的位置静态绑定的——这就是“词法”的含义。例如,函数 A 内定义的函数 B,无论 B 被在哪里调用,它的 outer 永远指向 A 的词法环境。
为什么叫“词法”环境:定义位置决定一切
看这个例子:
立即学习“Java免费学习笔记(深入)”;
function outer() {
const x = 10;
function inner() {
console.log(x); // 找得到!因为 inner 的词法环境 outer 指向 outer 的词法环境
}
return inner;
}
const fn = outer();
fn(); // 输出 10
这里 fn 是 inner 函数的引用,它被 outer 返回后,在全局调用。但 inner 仍能访问 x,不是因为它“记得” outer 被调用过,而是因为:inner 函数对象内部保存了对 outer 词法环境的引用(闭包的核心)。这个引用关系,在你写下 function inner(){...} 那一刻就固定了。
全局、函数、块级词法环境的区别
- 全局词法环境:outer 为 null,环境记录包含全局变量、函数声明;
- 函数词法环境:环境记录含参数、函数内 var/let/const 声明;outer 指向定义时的外层环境;
- 块级词法环境(如 if、for、{}):仅由 let/const 声明触发(var 不会),有自己的环境记录,outer 指向所在函数或外层块的词法环境。
注意:var 声明会提升并绑定到函数级词法环境,而 let/const 绑定到最近的块级词法环境,并存在暂时性死区(TDZ),这正是不同环境记录行为差异的体现。
调试小技巧:理解执行过程的关键线索
遇到变量找不到、报 ReferenceError 或输出 undefined,别急着查拼写,先问自己三个问题:
- 这个变量是在哪一行、哪个大括号里声明的?(定位词法环境层级)
- 当前代码处在哪个函数或块中?它的 outer 链依次指向哪里?(画出词法环境链)
- 该变量是用 var、let 还是 const 声明的?是否处于 TDZ?(判断是否进入对应环境记录)
Chrome DevTools 的 “Scope” 面板能直观显示当前执行点的词法环境链,配合断点观察,比纯脑补更可靠。



















