【JS】预编译(图解)

【JS】预编译(图解)
最新回答
凹凸有致丶

2026-01-01 11:44:27

预编译是 JavaScript 的一个重要特性,它在闭包之前可能难以理解。预编译有四句公式,只需记住这四句公式,便能理解预编译。这些公式放在文章结尾。本节内容篇幅较长,涉及较多概念。在学习预编译前,应记住:JavaScript 的声明和执行(赋值)是分开的两步操作,声明属于预编译阶段。

要了解预编译,首先应了解变量声明,它分为全局和局部。局部变量与作用域相关,后文将详细讲解。全局变量的声明有两条关键信息:

1、若变量未声明即被赋值,则该变量为全局变量所有。

2、所有声明的全局变量都是 window 对象的属性。

通过在控制台输出 window 对象,可以看到变量 a 的存在。如果输出 window.a,会直接输出 123,从而解析上述全局变量的两条规则。全局声明的变量称为全局变量,其作用域是全局。局部变量的作用域通常在函数内部。全局作用域称为 GO(Global Object),临时作用域称为 AO(Activation Object),而 GO 可以理解为 window 对象。GO 和 AO 与 JavaScript 的预编译概念密切相关。

【预编译公式】包含四部分:

1、创建 GO/AO 对象。

2、查找形参和变量声明,将变量和形参名作为 AO 的属性名,值为 undefined。

3、将实参值与形参统一。

4、在函数体内查找函数声明,将值赋予函数体。

下面的代码示例可以帮助理解 GO 和 AO:

在执行这段 JS 代码前,JavaScript 引擎会先对代码进行编译,即定义作用域的过程。最外层的作用域称为 GO,GO 现在包含 a 和 b,值都是 undefined。这完成了预编译公式中的前两句。由于这里是 GO,第三句公式无需特别考虑。接下来执行第四句公式,GO 将变为:

此时,b 的值已变为一个函数体。完成预编译公式后,GO 已完成定义。当预编译完成后,代码按顺序执行。此时执行第一行代码,因此 a 的值变为了 123。第三到第五行代码在 JS 执行时暂时忽略,因为它们在预编译时已提升。接着执行第七行代码,完成后执行第三到第五行代码。由于这些代码包含一个函数体,需要再次预编译,函数会产生一个 AO,并继承父函数作用域下的所有内容。

函数 b 会产生一个 AO,在这个过程中,函数 b 的 AO 首先检查是否有形参(aa),还检测到定义了一个变量 c。完成预编译公式前两条后,形成下图所示内容。接下来执行预编译公式第三条:将实参值与形参统一。因此,aa 的值在执行函数 b 时变为 123。最后,在函数 b 内寻找函数声明。由于无函数声明,最终形成下图所示内容。

至此,函数 b 的预编译完成,后续步骤仅执行,如变量 c 的赋值,最终使 c 的值为 888。这展示了 JavaScript 执行流程和预编译原理。记住【预编译公式】。

接下来是预编译的小案例,用于解析预编译概念(更多例子用于解析预编译)【案例 1】

执行上述代码时(包括预编译过程)会转化为下图所示。

【预编译公式】

函数声明具有同等地位。在预编译过程中,如果函数和变量名冲突,则函数优先。

关注公众号:我的 web 前端自救之路,回复 "加群",与技术大牛们交流。