执行上下文(参考 ECMA2024)
全局对象
https://262.ecma-international.org/#sec-global-object
The global object:
- is created before control enters any execution context .
- does not have a [[Construct]] internal method; it cannot be used as a constructor with the
**new**operator.- does not have a [[Call]] internal method; it cannot be invoked as a function.
- has a [[Prototype]] internal slot whose value is host-defined.
- may have host-defined properties in addition to the properties defined in this specification. This may include a property whose value is the global object itself.
翻译:
- 全局对象是控制器 control 进入任何执行上下文之前创建 - 创建时机
- 没有[[Construct]]内部方法,因此不能与 new 操作符一起用作构造函数。
- 没有[[call]]内部方法,不能作为函数调用。
- 宿主环境可以自定义全局对象的原型数据
- 除了本规范中定义的属性外,全局对象还可以有宿主环境定义的属性。 这可能包括一个属性,其值就是全局对象本身。(浏览器 window)
重点:
创建时机在进入任何执行上下文之前;
全局对象还可以有宿主环境定义的属性;(内置 API、window)
理解:
V8 会在真正开始执行 javascript 代码前,会初始化 js 运行所需要的基础环境,堆、栈空间、全局执行上下文、事件循环系统等
在进入全局执行上下文之前,全局对象会被创建。
伪代码
GlobalObject: {
window: GO,
String,
Array,
Object,
Date,
Settimeout
...
}TIP
执行上下文是什么?
执行上下文 Execution Context & 执行上下文栈 ECS
https://262.ecma-international.org/#sec-execution-contexts
An execution context is a specification device that is used to track the runtime evaluation of code by an ECMAScript implementation.
执行上下文 是一个规范设备,用于跟踪 ECMAScript 实现对代码的运行时评估。
An execution context is purely a specification mechanism and need not correspond to any particular artefact of an ECMAScript implementation. It is impossible for ECMAScript code to directly access or observe an execution context.
执行上下文纯粹是一个规范机制,不需要对应于 ECMAScript 实现的任何特定制品。ECMAScript 代码不可能直接访问或观察到执行上下文。
The execution context stack is used to track execution contexts. The running execution context is always the top element of this stack.
执行上下文堆栈 用于跟踪执行上下文。正在运行的执行上下文 始终是该堆栈的顶部元素。
A new execution context is created whenever control is transferred from the executable code associated with the currently running execution context to executable code that is not associated with that execution context. The newly created execution context is pushed onto the stack and becomes the running execution context.
每当控制权从与当前运行的执行上下文相关联的可执行代码转移到与该执行上下文无关的可执行代码时,就会创建一个新的执行上下文。 新创建的执行上下文被推入堆栈,成为运行中的执行上下文。-- 执行上下文的创建
理解 EC、ECS
执行上下文是在我们执行可执行文件时创建的 - 抽象概念
执行上下文栈,控制的执行上下文的状态的栈结构,从最新的 ECMA 规范理解:
- 执行上下文栈是用来跟踪执行上下文的,当前处于栈顶的是正在运行的执行上下文
- 调用其他关联的可执行代码时,会创建一个新的执行上下文,并将这个新的执行上下文压入栈顶
TIP
正如我们每次在执行函数前,都会创建函数执行上下文,当函数执行时,此执行上下文是处于调用栈顶部。执行完成后,这个函数的执行上下文就会被干掉。
INFO
在某个特定的时刻 只能执行特定的代码。一旦发生函数调用,当前的执行上下文必须停止 执行,并创建新的函数执行上下文来执行函数。当函数执行完成后,将 函数执行上下文销毁,并重新回到发生调用时的执行上下文中。所以需 要跟踪执行上下文——正在执行的上下文以及正在等待的上下文。最简 单的跟踪方法是使用执行上下文栈(或称为调用栈)。 -- js 忍者秘籍
执行上下文类型
- 全局执行上下文( GEC) :不在任何函数中的代码都位于全局执行上下文中,只有一个,当 JavaScript 程序开始执行时就已经创建了全局上下文。
- 函数执行上下文( FEC) :只有调用函数时,才会为该函数创建一个新的执行上下文,可以存在无数个,每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤。
- Eval 函数执行上下文(eval 代码) : 指的是运行在
eval函数中的代码,很少使用。
TIP
已经了解了 EC 是什么、以及它的类型,那么对于一个 EC 而言,它的内部结构是怎样的?
执行上下文的内部结构
可以简单理解,一个执行上下文结构内部会包含一系列的组件,这些组件在执行上下文执行过程中有不同的作用
ECMAScript 代码执行上下文的组件:
| Component | Purpose |
|---|---|
| code evaluation state | Any state needed to perform, suspend, and resume evaluation of the code associated with this execution context 执行、暂停和恢复与此 执行上下文 关联的代码所需的任何状态。 |
| Function | If this execution context is evaluating the code of a function object,then the value of this component is that function object. If the context is evaluating the code of a Script_ _or _Module_, the value is null. 如果这个执行上下文评估的是函数对象的代码,那么这个组件的值是该函数对象。如果执行的是 Script 和 Module,这个值是 null |
| Realm | The Realm Record from which associated code accesses ECMAScript resources. 关联代码访问 ECMAScript 资源的领域记录 在代码运行之前,所有 ECMAScript 代码都必须与一个领域相关联。 从概念上讲,一个领域包括一组内置对象、一个 ECMAScript 全局环境、在该全局环境范围内加载的所有 ECMAScript 代码,以及其他相关状态和资源。 |
| ScriptOrModule | The Module Record or Script Record from which associated code originates. If there is no originating script or module, as is the case for the original execution context created in InitializeHostDefinedRealm, the value is null. |
| LexicalEnvironment | Identifies the Environment Record used to resolve identifier references made by code within this execution context. 识别 环境记录,用于解析此执行上下文中代码对标识符的引用。 |
| VariableEnvironment | Identifies the Environment Record that holds bindings created by VariableStatements within this execution context. 用于标识环境记录,该环境记录保存由该执行上下文中的 VariableStatements 创建的绑定。 VariableStatements: var 声明的变量 |
| PrivateEnvironment | Identifies the PrivateEnvironment Record that holds Private Names created by ClassElements in the nearest containing class. null if there is no containing class. |
伪代码理解 EC 内部结构
ExecutionContext = {
codeEvaluationState, // 执行上下文在执行栈的状态
Function, // 执行的是函数时,值为函数对象,其他的都是null
Realm, // 领域:有一种全局环境的感觉
LexicalEnviroment: {...}, // 这块文档描述感觉不太清晰,理解不了。参考博客别的大佬理解的,暂且理解为非var声明的变量
VariableEnvironment: {...},// 该执行上下文中的VariableStatements
PrivateEnvironment: {...}, // 类的话,暂时先不理解,熟悉后可以画类的内存图看看
Generator: {...},
}重点理解关注的组件:
Function 函数
- 当前执行上下文是函数执行上下文时(评估函数对象代码的理解),值为函数对象,其他的都是 null
LexicalEnviroment 词法环境
- 官方描述实在没理解,有大佬明白的可以交流下
- 从其他文章看的:暂时过渡下 一般是
let,const声明的变量存储在该词法环境中,我理解是可以从词法环境的环境记录中找到非var标识符对应的映射值
VariableEnvironment 变量环境
- VariableStatements
var声明的变量可在变量环境的环境记录中找到对应的映射值
The LexicalEnvironment and VariableEnvironment components of an execution context are always Environment Records.
执行上下文中的 LexicalEnvironment 和 VariableEnvironment 组件始终是环境记录。
TIP
到此,我们已经对 EC 有一个大概的认知,也知道重点组件词法环境、变量环境其实就是是环境记录。那么什么是环境记录,怎么理解?
