作用域链由当前函数的活动对象、外层函数的活动对象(逐级向上)及全局对象组成,是函数定义时确定的词法结构,通过[[Environment]]属性指向定义时的词法环境,变量查找严格按此链从近到远进行。

作用域链是 JavaScript 查找变量的路径,不是运行时动态拼出来的,而是在函数定义时就确定下来的词法结构。它决定了你写的 console.log(x) 最终取到的是哪个 x。
作用域链由什么组成?
每个函数在创建时,内部会保存一个 [[Environment]] 属性,指向其**定义时所处的词法环境**。这个引用链加上当前执行时的活动对象(AO),就构成了作用域链。
- 最内层:当前函数的活动对象(含参数、
let/const/var声明) - 中间层:外层函数的活动对象(按嵌套层级逐级向上)
- 最外层:全局对象(如浏览器中的
window或globalThis)
变量查找怎么走?
引擎访问变量时,严格按作用域链从左到右、从近到远搜索,一旦命中就停止:
- 先查当前作用域(比如
inner函数体内有没有name) - 没找到,就顺着 [[Environment]] 去父级作用域(比如
outer)里找 - 再没找到,继续往上,直到全局;全程找不到就报
ReferenceError
为什么说“定义时决定”,而不是“调用时”?
因为作用域链绑定的是函数**写在哪**,不是**在哪被调用**。看这个例子:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
let value = 'global';
function foo() { console.log(value); }
function bar() { let value = 'bar'; foo(); }
bar(); // 输出 'global',不是 'bar'
foo 定义在全局,它的 [[Environment]] 指向全局环境,哪怕在 bar 里调用,也不会去 bar 的作用域里找 value。
块级作用域会影响作用域链吗?
不会直接加入链,但会影响变量声明的位置和可见性:
-
let/const在if或{}中声明,只属于那个块级作用域 - 该块不形成独立的作用域链节点,但它会限制变量在链中“被看到”的范围
- 比如
let x = 1写在if块里,foo()即使在同一个函数里也访问不到它

















