菜鸟入门第四天——JS预编译

前言

今天我将带领兄弟们学习预编译,这是许多大厂或面试时会经常出现的问题。希望通过我的讲解,能让兄弟们有所收获。

什么是预编译

预编译(Precompile)是指在程序执行之前,将程序源代码或某些代码片段提前进行编译,以便在运行时能够更快地执行其主要目的是提高程序的执行效率和性能。

预编译分为两种,一种叫做函数预编译,另一种叫做全局预编译,函数预编译发生在函数执行的前,全局预编译发生在页面加载完成时。

函数预编译

话不多说,下面我将通过这个案例来帮兄弟们分析函数预编译过程。

js 复制代码
function fn(a){
    console.log(a); // function a() {}
    var a = 123
    console.log(a); // 123
    function a() {} // 函数声明
    console.log(a); // 123
    var b = function() {} // 函数表达式
    console.log(b); // function () {}
    function d(){}
    var d = a
    console.log(d); // 123
}
AO:{
    // a: undefined 1 function a() {}   123,
    // b: undefined function () {},
    // d: undefined function d() {} 123,
}
fn(1)

预编译发生在函数执行之前 (四部曲)

1.创建AO对象 (Action Object)

在函数执行前,JavaScript引擎会创建一个特殊的对象,叫做Action Object(AO)。这个对象用于存储函数内的局部变量、形参以及函数声明。

js 复制代码
AO:{

}

2.找形参和变量声明,将变量声明和形参作为AO的属性名,值为undefind

JavaScript引擎会扫描函数内部,找到所有的形参和变量声明。然后,它将这些变量声明和形参作为AO对象的属性名,初始值为undefined。

js 复制代码
AO:{
    a: undefined
    b: undefined
    d: undefined
}

3.将实参和形参值统一

js 复制代码
AO:{
    a: undefined -> 1
    b: undefined
    d: undefined
}

4.在函数体内找函数声明,将函数名作为AO对象的属性名,值赋予函数体

js 复制代码
AO:{
    a:undefined -> 1 -> function a(){} -> 123
    b:undefined -> function b(){}
    d:undefined -> function d(){} -> 123
}

代码已经分析完了,下面给大家来看看运行结果:

全局预编译

下面我将通过另外一个案例来帮兄弟们分析全局预编译过程。

js 复制代码
GO:{
    global: undefined 100,
    fn: function fn() {}
}
var global = 100
function fn() {
    console.log(global);
}
AO:{
    //由于函数内部没有形参和声明变量,也没有函数声明,所以AO对象内为空
}
fn()

预编译发生在全局(三部曲)

1.创建 GO 对象(Global Object)

全局预编译阶段开始时,JavaScript引擎会创建一个全局对象,通常称为Global Object(GO)。这个对象是全局作用域中的根对象。

js 复制代码
GO:{

}

2.找变量声明,将变量声明作为GO的属性名,值为undefined

引擎会扫描全局作用域,找到所有的变量声明,并将它们作为GO对象的属性名,初始值设置为undefined。

js 复制代码
GO:{
    global: undefined,
    fn: function fn() {} 
}

3.在全局找函数声明,将函数名作为GO对象的属性名,值赋予函数体

在全局作用域内,引擎还会找到函数声明,将函数名作为GO对象的属性名,同时将整个函数体赋给这个属性。

js 复制代码
GO:{
    global: undefined -> 100
    fn: function fn(){}
}

代码已经分析完了,下面给大家来看看运行结果:

结语

让我们通过这张图来分析一下JS预编译的过程

当JavaScript程序开始执行,会创建一个全局执行上下文(GO)并将其推入调用栈的底部。当程序调用一个函数,函数的执行上下文(包括变量环境、词法环境)被创建,并被推入调用栈的顶部。当函数执行完毕,它的执行上下文从调用栈的顶部弹出,控制权返回到调用该函数的上下文。如果函数内部调用其他函数,这些函数的执行上下文按照调用顺序被依次推入和弹出调用栈。

相关推荐
濮水大叔7 分钟前
不必把 Vue3 写成“麻花”:从状态碎片到对象协作,重新理解 Zova 的前端心智模型
前端·typescript·vue3·ioc·tsx·zova
Vuji1 小时前
MCP: 一条 tool 调用链路的旅程
前端·人工智能
万少2 小时前
DeepSeek-V4-Flash 正式版上线了,但这 3 个坑我帮你提前踩了
前端·javascript·后端
明月_清风2 小时前
🚀 Palantir Foundry 本体论实战:当 Ontology 从"知识图谱"进化为"企业操作系统"
前端·后端
驳是2 小时前
入坑 Nginx,看这一篇就够了
前端
宁风NF2 小时前
JavaScript:网络请求与前端通信
开发语言·前端·javascript·网络·学习·ecmascript
明月_清风2 小时前
从概念到代码:用 Ontology 构建你的第一个知识图谱
前端·后端
程序员黑豆2 小时前
鸿蒙应用开发:AppStorage 全局状态存储用法教程
前端·harmonyos
猫猫不是喵喵.2 小时前
Vue3 中 computed 计算属性与 watch、watchEffect 监听
前端·javascript·vue.js
En^_^Joy3 小时前
Vue项目创建与入口配置全攻略
前端·vue.js·arcgis