前言
ECMAScript标准是深入学习JavaScript原理最好的资料,没有其二。
通过增加对ECMAScript语言的理解,理解javascript现象后面的逻辑,提升个人编码能力。
欢迎关注和订阅专栏 重学前端-ECMAScript协议上篇
基本概念
执行上下文对应着 协议的 9.4 Execution Contexts。
回顾之前的Agent相关章节, Agent代表了一组执行上下文、一个执行上下文栈、当前运行的执行上下文、一个Agent记录以及一个执行线程的集合。 所以执行上下文,执行上下文栈是归于某个Agent的。
执行上下文是一种的抽象概念,用于跟踪ECMAScript实现对代码的运行时评估。
执行上下文堆栈用于跟踪执行上下文,在任何时间点,每个实际执行代码的代理(Agent)最多只有一个执行上下文正在活动。
正在运行的执行上下文始终是这个堆栈的顶部元素。每当控制从与当前运行的执行上下文相关联的可执行代码转移到与该执行上下文不相关联的执行代码时,就会创建新的执行上下文。新创建的执行上下文被推送到堆栈上,并成为正在运行的执行上下文。
执行上下文的组件
所有执行上下文都有组件:
- 函数对象
- 领域 (Realm),就是一些基础资源的组合
组件 | 组件(中文) | 用途 |
---|---|---|
code evaluation state | 代码评估状态 | 一旦运行的执行上下文被挂起,一个不同的执行上下文可能会成为运行的执行上下文并开始评估其代码。稍后,挂起的执行上下文可能会再次成为正在运行的执行上下文,并在以前挂起的位置继续计算其代码 |
Function | 函数对象 | 如果上下文是评估函数对象的代码,其值为函数对象。如果是评估模块脚本或者是普通脚本,其值为null |
Realm | 领域 | 代码关联的领域记录。 |
ScriptOrModule | 脚本记录或者模块记录 | 代码关联的脚本记录或者模块记录。 初始化全局执行上下文时,这个执行上下文并没有一个特定的脚本或模块作为来源,因此它的脚本记录或者模块记录都为null。 |
协议对应如下表格内容:
代码执行上下文的组件
组件 | 组件(中文) | 用途 |
---|---|---|
LexicalEnvironment | 词法环境 | 负责存储标识符(如变量名、函数名)到变量引用的映射。词法环境的主要职责是处理作用域和变量查找。 |
VariableEnvironment | 变量环境 | 保存由VariableStatement (变量声明语句)创建的绑定关系。 |
PrivateEnvironment | 私有环境 | class私有属性环境记录 |
协议表格对应内容如下:

说明:
- LexicalEnvironment:其指向的环境记录,可能是函数环境记录,申明环境记录,对象环境记录等,其指向的环境记录,可以是保存 const/let/class等词法申明的绑定关系的环境记录,也可以保存其他绑定关系的环境记录。
- LexicalEnvironment 和 VariableEnvironment 可以指向同一个环境记录。
- 后面的标注符查询大都始于这个LexicalEnvironment指向的环境记录。
执行上下文的操作
本节先讲一些执行上下文协议规定的操作,下一节会结合代码来理解。
GetActiveScriptOrModule ( ) 【可跳过】
获取脚本记录或者模块记录,返回值可能是 脚本记录(Script Record), 模块记录( Module Record)或者 null.
模块记录(Module Record)和脚本记录(Script Record)是用来表示和管理模块或脚本的内部数据结构。
- Module Record:模块记录对应于一个ECMAScript模块,它包含了模块的导入声明、导出声明以及模块的实际代码。当模块被加载和执行时,与之关联的模块记录将生成一个执行上下文,用于跟踪模块内的变量、函数以及其他相关信息。
- Script Record:脚本记录则对应于非模块的常规JavaScript脚本文件。同样,它包含了脚本的所有源代码和相关的执行环境信息。
那还是来端代码和注释,更容易理解
typescript
javascript
复制代码
// 模块脚本 会有对应的 Module Record
<script src="./b.mjs" type="module">
// 常规脚本 会有对应的 Script Record
<script src="./a.js">
ResolveBinding ( name [ , env ] )
通过名字从环境记录中获取绑定关系(引用记录)。从传入的env环境记录 或者 当前执行上下文的词法环境中取查找,会用到环境记录中提到的操作 GetIdentifierReference(env, name, strict) ,找不到就会继续往外层环境记录找。
其逻辑很简单,找到对应的环境记录,然后调用 GetIdentifierReference。

GetThisEnvironment ( )
获取提供this
关键字绑定关系的环境记录。
至于原因吗,当然箭头函数创建的环境记录本身没有提供 this 绑定。 其会一层一层往外找,直到找到位置。

ResolveThisBinding ( )
从当前执行中的上下文中 的 环境记录中 获得 this 的值,也就是取环境记录中[[ThisValue]]
,这是一个值,不是引用记录。
不同环境记录的获取逻辑是不一样的。

以函数环境记录为例:

GetNewTarget ( ) 【可跳过】
获取环境记录上的 [[NewTarget]]
属性。可从之前的环境记录的字段知道,只有函数环境记录上才有。

GetGlobalObject ( )
从当前 领域(Realm Record) 中获取全局对象。

协议本身也是一直在变化的,比如如下对照:

关系
执行上下文(Execution Context)、环境记录(Environment Record)和引用记录(Reference Record)紧密关联,它们共同服务于变量和函数作用域的管理以及代码执行的跟踪。
- 执行上下文
执行上下文执行代码时创建的抽象概念,每次执行代码(如全局代码、函数调用、eval调用等)时,都会创建一个新的执行上下文,并将其推入执行上下文栈中。
其包含三种组件(环境记录) Additional State Components for Generator Execution Contexts:
组件 | 目的 |
---|---|
LexicalEnvironment | 用于标识解决此执行上下文中代码所作标识符引用所使用的环境记录。在词法作用域中查找变量时,引擎会大多数情况从当前执行上下文的词法环境记录中查找变量绑定。 |
VariableEnvironment | 用于标识在此执行上下文中由VariableStatements创建的绑定所在的环境记录。它管理var关键字声明的变量 ,以及在全局作用域或函数作用域内定义的变量。 |
PrivateEnvironment | 用于标识最近包含类中由ClassElements创建的Private Names所在的PrivateEnvironment Record。如果不存在包含类,则值为null。PrivateEnvironment记录负责存储和管理类的私有字段和方法,确保这些私有成员只能在类内部访问。 |
- 环境记录 (后面的章节会详解介绍)
环境记录是用来存储和管理变量与函数绑定的地方。环境记录维持了一种绑定关系,使得代码能够在相应的作用域内找到并操作变量。
- 引用记录 (后面的章节会详解介绍)
引用记录是对变量引用的一种抽象表示,它记录了变量名和对应的环境记录及绑定的位置信息。
当需要查找变量时,会通过引用记录来定位到正确的环境记录,并在该记录中查找绑定的值。引用记录主要用于实现变量查找机制,尤其是当涉及作用域链和闭包时。
总结起来,执行上下文是整个执行环境的容器,其中包含的环境记录负责存储变量和函数的绑定信息,而引用记录则协助引擎高效准确地定位和操作这些绑定。三者共同协作,保证了代码的正确执行和作用域规则的遵守。