作用域链在执行上下文创建阶段即完成初始化,由函数定义时的词法位置静态决定,通过词法环境的outer引用逐层链接形成,不依赖运行时调用方式。

作用域链在执行上下文创建阶段就已完成初始化,它不是运行时动态拼凑的,而是由函数定义时的词法位置静态决定,并在进入执行上下文的“创建阶段”被一次性构建出来。
作用域链的初始化时机和依据
作用域链的初始化发生在函数被调用、JS引擎为其创建执行上下文的**创建阶段(Enter Execution Context)**,此时尚未执行任何函数体内的代码。它的构建不依赖于调用方式或运行时环境,只取决于函数在源码中定义的位置——这就是“词法作用域”的核心含义。
具体来说,引擎会做以下事情:
- 根据当前函数的 外层词法环境(即函数声明时所处的作用域),获取其词法环境(Lexical Environment)的 外部环境引用(Outer Lexical Environment Reference);
- 将该引用作为当前执行上下文词法环境的
outer属性值; - 这个
outer指针指向父级执行上下文的词法环境,逐层向上链接,最终形成一条从当前到全局的链式结构——即作用域链。
词法环境与变量环境的分工影响作用域链
ES6 后,执行上下文内部明确区分了 词法环境(LE) 和 变量环境(VE)。但要注意:只有词法环境参与作用域链的构成,变量环境不对外提供查找能力。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 词法环境存储
let/const、class、import和块级声明,其outer引用直接构成作用域链的骨架; - 变量环境仅用于存放
var声明和函数声明,它本身没有outer链,也不参与变量查找流程; - 变量查找始终从当前词法环境开始,若未找到,则沿
outer引用向上遍历词法环境链,直到全局词法环境。
一个典型初始化过程示例
考虑如下代码:
function outer() {const x = 10;
function inner() {
console.log(x); // 访问外层变量
}
inner();
}
当调用 inner() 时:
- 引擎为
inner创建新的函数执行上下文; - 在创建阶段,引擎检查
inner的定义位置(在outer函数体内),于是将inner的词法环境的outer指向outer当前执行上下文的词法环境; -
outer的词法环境又将其outer指向全局词法环境; - 这样,
inner的作用域链就确定为:[inner-LE] → [outer-LE] → [global-LE]。
闭包如何“冻结”作用域链
如果函数返回后仍被引用(如赋值给外部变量),它的执行上下文不会被销毁,其中的词法环境及其 outer 引用保持有效。这意味着作用域链被完整保留下来——这正是闭包能持续访问外层变量的根本原因。
例如:return inner; 后,inner 依然持有对 outer 词法环境的引用,即使 outer 已执行完毕。

















