Js的预编译你了解多少呢?
2024-10-09
1217 字约 5 分钟
...预编译
预编译是指在程序运行之前,先对程序进行一些处理,例如预处理、编译、链接等,以便提高程序运行效率和减少运行时的错误。
编译的作用:提高程序的效率和稳定性,减少程序在运行过程中可能出现的错误,并提高程序的可维护性和可扩展性。
作用域
作用域是函数身上的属性 [[scope]](给js引擎访问的,我们拿不到 -- 隐式属性),用于存储函数中的有效标识符。
作用域链
作用域是执行期上下文对象的集合,这种集合呈链式连接,我们把这种链关系称之为作用域链。
- GO (Global Object):函数执行上下文对象;
- AO (Activation Object):全局执行上下文对象;(可访问GO)
代码
function a() {
function b(){
var b = 22
console.log(a)
}
var a = 111
b()
}
var glob = 100
a()
作用域链

分析
全局定义了函数a和global,形成如图GO,此时a[[scope]]的0指向GO,函数a内定义了函数b和a,形成如图AO,此时a[[scope]]的0指向自己的AO,1指向GO,函数b定义了b,形成如图AO,b[[scope]]的0指向自己的AO,1指向a[[scope]]。
声明提升
- 变量声明,声明提升(上一篇文章提到过)
- 函数声明,整体提升
test()
function test() {
var a = 123
console.log(a)
}
上述代码相当于:
function test() {
var a = 123;
console.log(a);
}
test();
预编译的分析(重点!)
定义
- 发生在全局:
- 创建GO对象
- 找变量声明,将变量名作为GO的属性名,值为undefined
- 在全局找函数声明,将函数名作为GO的属性名,值为该函数体
- 发生在函数体内:
- 创建一个AO对象
- 找形参和变量声明,将形参和变量名作为AO的属性名,值为undefined
- 形参和实参统一
- 在函数体内找函数声明,将函数名作为AO的属性名,值为该函数体
步骤
全局预编译-->GO-->执行,碰见函数-->函数预编译-->AO-->执行函数
实例一
代码
var a = 1
function fn(a) {
var a = 2
function a() {}
console.log(a)
}
fn(3)
分析
- 首先进行全局预编译-->GO
- GO:{ }
- GO:{ a:undefined }
- GO:{ a:undefined , fn:function(a){ var a = 2; function a() {}; console.log(a); }
- 执行
- GO:{ }
- GO:{ a:1 }
- GO:{ a:undefined , fn:function(a){ var a = 2; function a() {}; console.log(a); }
- 碰见函数,进行函数预编译-->AO
- AO:{ }
- AO:{ a:undefined;(这里是a:undefined;(形参)a:undefined;(变量)) }
- AO:{ a:3(fn(3)), }
- AO:{ a:function(){}, (a:3;a:function(){};最后得出的结果) }
-
执行函数
AO:{ a:2, }

实例二
代码
function fn() {
console.log(a);
var a = 123;
console.log(a);
function a() {};
console.log(a);
var b = function(){};
console.log(b);
function c(){};
var c = a;
console.log(c);
}
fn(1);
分析
GO:{
fn:function fn(){}
}
AO:{
a:undefined-->undefined-->1-->function a(){}, -->123,
b:undefined, -->function b(){},
c:undefined-->function c(){}, -->123
实例三
代码
function test(a, b) {
console.log(a);
c = 0
var c;
a = 3
b = 2
console.log(b);
function b() {}
console.log(b);
}
test(1)
分析
GO:{
test:function
}
AO:{
a:undefined-->1, -->3
b:undefined-->undefined-->function b(){}, -->2
c:undefined, -->0
}
如果您觉得这篇文章有帮助,请点个赞吧~
相关文章
更多文章 →javascript2025-09-18
JavaScript 的多线程能力:Worker
如果你写过一些计算量稍大的 JavaScript 代码,比如图像处理、大量数据排序或者复杂的算法,你几乎肯定遇到过浏览器“卡死”的现象。点击页面没反应,动画也停了,就像整个世界都静止了。 这就是主线程被阻塞的典型后果。因为主线程既要负责执行 JavaScript,又要负责渲染页面、响应用户操作,一旦它被繁重的计算任务占满,就无暇顾及其他,用户体验便直线下降。 这个问题的根源,正是“主线程是单线程的”。那么,如何解决呢? 答案很简单:把这...
学习面试
javascript2025-09-10
手把手教你实现一个EventEmitter
你是不是也遇到过这种情况:代码里各种事件监听和触发,回调函数套了一层又一层,最后自己都理不清哪个事件先触发、哪个后触发了? 别担心,今天我就带你从零开始实现一个自己的事件触发器(EventEmitter),让你彻底掌握事件驱动的精髓,代码清晰度直接提升200%! 为什么要懂EventEmitter? 先说说为什么我们要关心这个。Node.js的核心就是事件驱动,比如文件读写、网络请求,都是通过事件来处理的。不会EventEmitter,...
学习面试
javascript2025-08-09
Web Worker 多线程魔法
你是否曾遇到过网页因为复杂计算而卡顿的情况?今天,让我们一起探索Web Worker的神奇世界,看看如何用多线程技术解决性能瓶颈,并实现流畅的图片压缩功能! 为什么需要Web Worker? 想象一下,你在一个繁忙的餐厅里,只有一位服务员(主线程)负责点餐、上菜、结账所有工作。当客人突然暴增时,这位服务员就会手忙脚乱,其他客人只能干等着… 这就是JavaScript的现状—— 单线程 !所有任务都在一个线程中排队执行,一旦遇到复杂计算(...
学习面试
javascript2025-08-07
🌐AST抽象语法树
AST 是前端开发中一个非常重要的概念,它就像是代码的“编译器”,能够帮助我们理解和操作代码。本文将深入探讨 AST 的原理和应用,带你从零开始了解 AST。 一、什么是 AST? AST(抽象语法树)是一种树形结构,用于表示程序代码的语法结构。它将代码分解为一系列的节点,每个节点代表代码中的一个元素,如变量、函数、表达式等。AST 是编译器和解释器的基础,也是代码分析和转换的关键工具。 1\. AST 的结构 AST 的结构通常包括以...
学习面试
javascript2025-08-05
打字机效果是如何实现的
分析效果 使用 AI 对话的时候,文字是一个字一个字蹦出来的?它不是等所有内容生成完毕后一次性展示,而是以一种流畅、实时的“打字机”效果呈现,这种体验的背后,隐藏着一种高效的Web技术。它就是 服务器推送事件(Server Sent Events,简称 SSE) 什么是 SSE 从根本上说,SSE 是一种允许服务器 单向 、 持续 地向客户端(浏览器)推送数据的Web技术。 可以把它想象成一个 电台广播 : 服务器 是广播电台,持续不断...
学习面试
javascript2025-08-04
Promise 从原理到实现
前言 是 异步编程的核心概念之一,它为我们提供了一种更优雅的方式来处理异步操作。 本文将全面剖析 的工作原理,并逐步实现一个符合 规范的 。 正文 一、Promise 基础概念 代表一个异步操作的最终完成(或失败)及其结果值。它有 种状态: 1. pending : ,既不是成功,也不是失败状态 2. fulfilled :意味着操作 完成 3. rejected :意味着操作 状态一旦改变就不能再变,只能从 变为 ,或从 变为 。 二...
学习面试
评论
请登录后发表评论
去登录