javascript变量查找按作用域链从内向外逐级搜索,定义时确定链结构,先查当前词法环境记录,未找到则沿outer引用向上,直至全局;未声明则抛referenceerror。

JavaScript 中变量的查找顺序由作用域链(Scope Chain)决定,它是一条从当前执行上下文开始、逐级向上回溯到全局作用域的链式结构。查找时始终从最内层作用域(如函数内部)开始,一层层向外找,直到找到第一个匹配的变量声明;若全局作用域也未找到,则报 ReferenceError。
作用域链的形成时机与结构
作用域链在函数**定义时**就已确定(基于词法作用域),而非调用时。每个函数对象内部都保存着其定义时所在环境的词法作用域引用(即 [[Environment]] 内部槽)。执行时,JS 引擎将当前执行上下文的词法环境(Lexical Environment)与其外部词法环境链接起来,构成一条链。
- 全局代码的作用域链只包含全局词法环境
- 函数执行时,作用域链 = 当前函数的词法环境 + 外部词法环境(可能嵌套多层)+ 全局词法环境
- 闭包的本质就是内部函数保留了对外部函数词法环境的引用,使该环境不会被回收
变量查找的具体过程
当访问一个标识符(如 x)时,引擎按以下顺序搜索:
- 先在当前执行上下文的**词法环境记录(Environment Record)**中查找(如
let/const声明的绑定) - 未找到则沿
outer引用进入上一级词法环境,重复查找 - 最终到达全局环境;若仍无定义,抛出
ReferenceError - 注意:查找只看声明位置,不看赋值或调用位置。哪怕函数在别处调用,也仍沿定义时的外层链查找
常见影响查找顺序的关键细节
以下情况会显著改变变量是否可访问或取到哪个值:
-
var 声明存在变量提升,但作用域仍是函数级:即使在
if块中声明,也会被提升至函数顶部,整个函数内都可访问(值可能为undefined) - let/const 有暂时性死区(TDZ):在声明语句之前访问会直接报错,不进入作用域链查找流程
- 函数参数和函数声明也会加入当前词法环境:同名时,参数 > 函数声明 > var 声明(但后者会被提升覆盖)
-
with 和 catch 子句会临时扩展作用域链:但因性能与可读性问题,严格模式下禁用
with,且应避免依赖它们影响查找逻辑
如何验证作用域链行为
虽然无法直接打印完整作用域链,但可通过典型例子观察效果:
- 嵌套函数中访问外层变量 → 证明链式向上查找
- 同名变量在不同层级声明 → 确认“就近原则”(最先找到即停止)
- 闭包返回内部函数并调用 → 外层变量仍可访问,说明环境被保留
- 使用
eval(非严格模式)可动态创建变量并注入当前作用域 → 改变查找结果(但应避免)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











