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

相关推荐
大怪v5 小时前
AI抢饭?前端佬:我要验牌!
前端·人工智能·程序员
新酱爱学习5 小时前
字节外包一年,我的技术成长之路
前端·程序员·年终总结
小兵张健5 小时前
开源 playwright-pool 会话池来了
前端·javascript·github
IT_陈寒8 小时前
Python开发者必知的5大性能陷阱:90%的人都踩过的坑!
前端·人工智能·后端
codingWhat9 小时前
介绍一个手势识别库——AlloyFinger
前端·javascript·vue.js
代码老中医9 小时前
2026年CSS彻底疯了:这6个新特性让我删掉了三分之一JS代码
前端
不会敲代码19 小时前
Zustand:轻量级状态管理,从入门到实践
前端·typescript
踩着两条虫9 小时前
VTJ.PRO 双向代码转换原理揭秘
前端·vue.js·人工智能
扉川川9 小时前
OpenClaw 架构解析:一个生产级 AI Agent 是如何设计的
前端·人工智能
远山枫谷9 小时前
一文理清页面/组件通信与 Store 全局状态管理
前端·微信小程序