变量查找严格遵循执行上下文构建的作用域链,从当前词法环境开始逐层向外匹配;词法环境含环境记录和指向外层的outer reference,形成静态确定的作用域链;var提升初始化为undefined,let/const存在tdz不可访问。

变量查找不是靠“猜”或“就近原则”,而是严格遵循执行上下文构建的作用域链,从当前词法环境开始,逐层向外匹配绑定。
执行上下文是变量查找的起点
每次函数调用或脚本启动,JS引擎都会创建一个执行上下文,它包含三个关键部分:变量对象(或变量环境)、词法环境、this值。其中,词法环境直接决定变量能“看到谁”——它内部记录了当前作用域声明的变量(let/const),并持有一个指向外层词法环境的引用(Outer Reference)。这个引用链,就是作用域链的物理基础。
- 全局执行上下文的词法环境指向 null(链尾)
- 函数执行上下文的词法环境指向其定义时的外层词法环境(不是调用时)
- 块级作用域(如 if、for 内的 let)也会生成独立词法环境,嵌套在当前函数环境中
作用域链按词法嵌套顺序静态确定
JavaScript采用词法作用域,函数的作用域在代码写完时就固定了,和调用位置无关。比如嵌套函数 inner 定义在 outer 内部,它的作用域链永远是:[inner 的词法环境] → [outer 的词法环境] → [全局词法环境],哪怕 inner 被返回并 elsewhere 调用,这条链也不变——这就是闭包的根源。
- 查找变量时,引擎先查当前词法环境的环境记录(比如 let z = 30)
- 没找到就顺着 Outer Reference 去上一层词法环境查(比如 y)
- 直到全局环境;仍找不到就报 ReferenceError(非严格模式下对未声明变量赋值会挂到全局对象,但这是历史包袱,应避免)
var 与 let/const 查找行为不同,根源在绑定状态
作用域链路径相同,但能否成功访问,取决于变量是否已“准备好”。var 声明会被提升并初始化为 undefined,所以查找能成功,只是值为 undefined;而 let/const 虽然也提升(绑定已注册),但在声明语句执行前处于暂时性死区(TDZ),此时访问会直接抛错——不是没找到,而是“找到了但不可用”。
-
console.log(a); var a = 1;→ 输出 undefined(var 提升 + 初始化) -
console.log(b); let b = 2;→ 报 ReferenceError(TDZ 拦截) - 两者都在作用域链中存在,区别在于绑定是否进入“可读取”状态
变量对象与词法环境分工协作
在函数执行上下文中,变量环境(Variable Environment)主要处理 var 和函数声明,而词法环境(Lexical Environment)负责 let、const 和 this。它们共同构成完整的作用域视图。变量查找优先走词法环境链;若涉及 var 变量,引擎会同时检查变量环境,但最终仍统一纳入作用域链逻辑——因为变量环境本身也通过内部引用接入该链。
- 函数参数、var 声明归变量环境管理
- let/const、块级结构、this 绑定归词法环境管理
- 两者都参与作用域链构建,共同支撑变量查找全过程
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











