前端进阶之说一说你对JS上下文栈和作用域链的理解?

栏目: JavaScript · 发布时间: 5年前

内容简介:词法环境(Lexical Environment)是一种规范类型,用于根据环境记录(Environment Record)记录在其关联的词汇环境范围内创建的标识符绑定。其一共分了5类,分别如下:执行上下文(Execution Contexts)是一种规范设备,用于跟踪ECMAScript实现对代码的

词法环境(Lexical Environment)是一种规范类型,用于根据 ECMAScript 代码的 词法嵌套结构定义标识符特定变量函数 的关联。 词法环境(Lexical Environment)环境记录(Environment Record)外部词汇环境的可能为null的引用 组成。通常, 词法环境(Lexical Environment)ECMAScript 代码的某些特定语法结构相关联,并且每次评估此类代码时都会创建新的词法环境。

环境记录(Environment Record)记录在其关联的词汇环境范围内创建的标识符绑定。其一共分了5类,分别如下:

  • 声明环境记录(Declarative Environment Records) :每个 声明环境记录(Declarative Environment Records) 都与 ECMAScript程序作用域 相关联,其中包含: 变量,常量,let,类,模块,导入和/或函数声明声明环境记录(Declarative Environment Records) 绑定由其范围内包含的声明定义的标识符集。
  • 对象环境记录(Object Environment Records)对象环境记录(Object Environment Records) 记录每个对象增删改查。
  • 函数环境记录(Function Environment Records)函数环境记录(Function Environment Records) 每个 函数作用域 以及 上下文环境 的具体情况。
  • 全局环境记录(Global Environment Records)全局环境记录(Global Environment Records) 用于表示所有 ECMAScript Script元素 共享的 最外层作用域 。全局环境记录提供内置全局变量,全局对象的属性以及脚本中发生的所有顶级声明的绑定。
  • 模块环境记录(Module Environment Records)模块环境记录(Module Environment Records) 用于表示 ECMAScript模块 的外部范围以及绑定情况。

词法环境分了三类:

  • 全局环境(global environment)全局环境(global environment) 是一个没有外部环境的 词法环境 全局环境(global environment) 的外部环境引用为 null 全局环境(global environment) EnvironmentRecord(环境记录) 可以预先填充标识符绑定,并包括关联的全局对象,其属性提供一些全局环境的标识符绑定。在执行 ECMAScript 代码时,可以向全局对象添加其他属性,并且可以修改初始属性。
  • 模块环境(module environment)模块环境(module environment) 也是一个 词法环境 ,它包含模块顶级声明的绑定。它还包含模块显式导入的绑定。模块环境的外部环境是 全局环境(global environment)
  • 函数环境(function environment)函数环境(function environment) 也是一个 词法环境 ,对应于 ECMAScript 函数对象的调用。功能环境可以建立新的此绑定。函数环境还捕获支持超级方法调用所需的状态。

执行上下文(Execution Contexts)

执行上下文(Execution Contexts)是一种规范设备,用于跟踪ECMAScript实现对代码的 运行时(runtime) 评估。在任何时间点,每个代理程序最多只有一个执行上下文实际执行代码。这称为 代理程序运行执行上下文(running execution context])

执行上下文堆栈(execution context stack)用于跟踪执行上下文。正在运行的执行上下文始终是此堆栈的顶级元素。每当控制从与当前运行的执行上下文相关联的可执行代码转移到与该执行上下文无关的可执行代码时,就创建新的执行上下文。新创建的执行上下文被压入堆栈并成为正在运行的执行上下文。

所有执行上下文的状态组件(State Components)

组件 作用
代码评估状态 执行,暂停和恢复与此执行上下文关联的代码的评估所需的任何状态。
函数 如果此执行上下文正在评估函数对象的代码,则此组件的值是该函数对象。如果上下文正在评估脚本或模块的代码,则该值为null。
领域(Realm) 相关代码从中访问ECMAScript资源的领域(Realm)记录。
脚本或模块 相关代码所源自的模块记录或脚本记录。如果没有原始脚本或模块,就像在 InitializeHostDefinedRealm (原生方法) 中创建的原始执行上下文的情况一样,该值为 null

作用域链(Scope chain)

作用域负责收集和维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。-- 《你不知道的JavaScript(上卷)》

从上面两个话题,我们可以知道,除 全局作用域(global scope) 外,每个范围始终连接到其背后的一个或多个范围,形成链或层次结构。 全局作用域(global scope) 没有任何父级,这也是有意义的,因为它位于层次结构的顶部。

我们看下面的代码:

const bestAvenger = "Iron man";
function a() {
  const bestActor = "Neymar";
  console.log(bestAvenger); // output:Iron man
    
  function c() {
    const bestProgrammingLanguage = "Html";
    console.log(bestActor); // output:Neymar
    b();
  }
  c();
}
function b() {
  console.log(bestProgrammingLanguage); //**not defined error**
}
a();
复制代码

上面的代码会报错如下: bestProgrammingLanguage is not defined.

如上所述, 作用域链(Scope chain) 始终是 词法 创建的。 作用域 的父节点由 执行上下文(函数) 在代码中的词法或物理位置定义。

上面代码的 作用域链(Scope chain) 如下:

词法环境 作用域链
全局作用域下的G G = G
G下的A A = A + G
G下的B B = B + G
G下的A,A下的C C=C+A => C+A+G

其实总结起来就是:

  • 每当编译器遇到变量或对象时,它都会遍历当前执行上下文的整个 作用域链(Scope chain) ,以查找它。如果没有在那里找到它,它遍历 原型链(prototype chain) ,如果它也没有找到,它会抛出未定义的错误。
  • 编译器通过查看函数在代码中的位置来创建函数的作用域。
  • 编译器创建称为 作用域链(Scope chain) 的等级层次结构, 全局作用域(Global Scope) 位于此层次结构的顶部。
  • 当代码中使用变量时,编译器会向后查看作用域链,如果找不到,则抛出未定义的错误。
如果你、喜欢探讨技术,或者对本文有任何的意见或建议,你可以扫描下方二维码,关注微信公众号“

”,随时与鱼头互动。欢迎!衷心希望可以遇见你。


以上所述就是小编给大家介绍的《前端进阶之说一说你对JS上下文栈和作用域链的理解?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法:C语言实现

算法:C语言实现

塞奇威克 / 机械工业出版社 / 2006-9 / 69.00元

本书是Sedgewick彻底修订和重写的C算法系列的第一本。全书分为四部分,共16章,第一部分“基础知识”(第1-2章)介绍基本算法分析原理。第二部分“数据结构”(第3-5章)讲解算法分析中必须掌握的数据结构知识,主要包括基本数据结构,抽象数据结构,递归和树。一起来看看 《算法:C语言实现》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具