关于outer与[[scopes]]的关系及相关作用机制的技术咨询
关于[[Scopes]]、outer属性与作用域链的关系解析
核心概念梳理
- [[Scopes]]:这是函数对象的内部隐藏属性,在函数定义的那一刻就被确定下来,它是一个数组,存储的是函数定义时所在的所有外层词法环境的集合,顺序是从最近的外层环境到全局环境。简单说,就是函数定义时“能访问到”的所有上层作用域的快照。
- outer属性:是执行上下文的词法环境的一个属性,当函数执行、创建执行上下文时,当前词法环境的
outer会指向[[Scopes]]数组中的第一个元素(也就是最近的外层词法环境),而外层词法环境的outer又会指向它自己的外层(即[[Scopes]]数组的下一个元素),以此类推形成链式结构。 - 作用域链:本质上是由当前执行上下文的词法环境,加上通过
outer属性串联起来的所有外层词法环境共同组成的链条,变量查找时会沿着这条链从近到远依次检索。
你的问题解答
1. [[Scopes]]维护的数组是否包含outer链上的所有词法环境?
是的,但要明确:[[Scopes]]存储的是函数定义时的外层词法环境集合,执行时的outer链是基于[[Scopes]]构建的。执行时,当前函数的词法环境(包含自身定义的变量、参数)会作为作用域链的起点,它的outer指向[[Scopes]]的第一个元素,后续的outer节点完全对应[[Scopes]]数组里的元素,直到全局环境。所以outer链上的所有外层环境都来自[[Scopes]]数组。
2. 二者的关联是什么?
[[Scopes]]是构建执行时outer链的基础模板:
- 函数定义阶段,JS引擎会捕获当前所在的所有外层词法环境,存入[[Scopes]]数组,这就是JS“静态作用域”的体现——作用域在函数定义时就确定,而非执行时。
- 函数执行阶段,创建执行上下文时,当前词法环境的
outer会直接指向[[Scopes]]数组的第一个元素,后续的outer链接就沿着[[Scopes]]里的环境依次向上,最终形成完整的作用域链。
3. 作用域链的确定是否与执行上下文相关,还是执行上下文创建时就直接关联作用域链?
作用域链的确定完全和执行上下文绑定,并且是在执行上下文创建时就完成关联的:
- 当函数开始执行,JS引擎会创建对应的执行上下文,此时会生成当前函数的词法环境(包含内部变量、参数等),然后将这个词法环境的
outer指向[[Scopes]]的第一个元素,串联起所有外层环境,形成完整的作用域链。 - 换句话说,每个执行上下文都有自己专属的作用域链,这条链就是由当前词法环境加上基于[[Scopes]]构建的outer链组成的。
直观示例
const globalVal = '全局变量'; function parent() { const parentVal = '父级变量'; function child() { const childVal = '子级变量'; console.log(childVal, parentVal, globalVal); } return child; } const childFunc = parent(); childFunc();
- 当
child函数定义时,它的[[Scopes]]数组是[parent函数的词法环境, 全局词法环境] - 当
childFunc()执行时,创建执行上下文:- 生成当前词法环境(包含
childVal) - 当前词法环境的
outer指向[[Scopes]]的第一个元素(parent的词法环境) - parent的词法环境的
outer指向[[Scopes]]的第二个元素(全局词法环境)
- 生成当前词法环境(包含
- 最终作用域链:
child的词法环境 → parent的词法环境 → 全局词法环境,变量查找就沿着这条链进行。
内容的提问来源于stack exchange,提问作者江定玺
相关产品推荐
相关产品推荐

