程序执行过程
2025年2月6日大约 2 分钟
程序执行过程
// 全局代码
const glo_const = 1
let glo_let = 2
var glo_var = 3
class Glo_class{}
function glo_fn(){ // ③
// 位于函数体内声明语句
let inner_fn_let = 4
var inner_fn_var = 5
}
if(true){ // ④
// 位于块内的声明语句
let block_let = 6 // ⑤
var block_var = 7 // ⑥
function block_fn(){} // ⑦
}
初始化Realm环境:InitializeHostDefinedRealm
创建全局执行上下文、realm记录器。realm记录器包含全局对象、全局环境记录器、固有对象。
图示

解析脚本
每一段脚本执行前,需要先解析脚本,将其转换为解析树。返回一个脚本记录器。
脚本求值
- 创建ECMAScript代码执行上下文(scriptContext) ,设置scriptContext的词法环境、变量环境指向全局环境记录器等。
- 接着推送到执行上下文栈,使其成为运行中的执行上下文。
- 然后进行全局声明实例化,最后对脚本语句求值。
全局声明实例化以后的调用栈。

全局声明实例化
声明实例化,不等于初始化,只有执行到对应的位置,才能知道确切的值。
GlobalDeclarationInstantiation
- 调用LexicallyDeclaredNames 、VarDeclaredNames语义收集标识符。
- 从结果来看LexicallyDeclaredNames只会收集let、const声明语句(只会处理Declaration)的标识符,会忽略所有的函数声明。
- VarDeclaredNames对语句递归的调用,收集可见var声明、函数声明的标识符。不会处理函数和类中的。
- 如果词法声明和变量声明的连接有重复项,则抛出 SyntaxError 异常。
- 调用VarScopedDeclarations语义收集变量声明语句varDeclarations,调用LexicallyScopedDeclarations 语义收集词法声明语句 lexDeclarations。
- 最后得到三个列表:lexDeclarations、varDeclarations、functionsToInitialize。根据标识符的类型进行绑定
- 对于lexDeclarations中的标识符,绑定到全局环境记录器的[[DeclarativeRecord]]字段上。
- 对于functionsToInitialize,实例化相应的函数对象,并绑定到全局环境记录器的[[ObjectRecord]]字段上((实际上是成为全局对象的属性))。
- 对于varDeclarations中的标识符,绑定到全局环境记录器的[[ObjectRecord]]字段上((实际上是成为全局对象的属性))。
关于严格模式
非严格模式函数标识符会被实例化并初始化为undefined,严格模式下函数不会被实例化。
全局声明实例化以后的调用栈。
