菜鸟入门第四天——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)并将其推入调用栈的底部。当程序调用一个函数,函数的执行上下文(包括变量环境、词法环境)被创建,并被推入调用栈的顶部。当函数执行完毕,它的执行上下文从调用栈的顶部弹出,控制权返回到调用该函数的上下文。如果函数内部调用其他函数,这些函数的执行上下文按照调用顺序被依次推入和弹出调用栈。

相关推荐
Mintopia28 分钟前
Three.js 在数字孪生中的应用场景教学
前端·javascript·three.js
夕水44 分钟前
自动化按需导入组件库的工具rust版本完成开源了
前端·rust·trae
JarvanMo2 小时前
借助FlutterFire CLI实现Flutter与Firebase的多环境配置
前端·flutter
Jedi Hongbin2 小时前
echarts自定义图表--仪表盘
前端·javascript·echarts
凯哥19702 小时前
Sciter.js指南 - 桌面GUI开发时使用第三方模块
前端
边洛洛2 小时前
对Electron打包的exe文件进行反解析
前端·javascript·electron
财神爷亲闺女2 小时前
js 实现pc端鼠标横向拖动滚动
前端
用户2031196600962 小时前
sheet在SwiftUI中的基本用法
前端