五分钟——快速了解JS代码执行前的“预编译阶段”

这篇博客探讨了JavaScript中的“预编译阶段”,实际上应称为“预处理”。主要讲解了词法环境和变量提升的概念,解释了为何人们认为JS有预编译阶段。在词法分析阶段,词法环境对象被创建,存储局部变量,并在代码定义时确定。变量声明和函数声明在词法环境中表现不同,函数声明会立即完成初始化。通过实例展示了变量和函数在词法环境中的变化过程,帮助读者理解JS的执行机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

莫名奇妙出现的"预编译阶段"

众所周知,JS是一种解释型语言而非编译型语言

(下面非常简要地说明一下两种区别)

简要区分编译型语言和解释型语言: 计算机是不能理解高级语言的,更不能执行高级语言,它只能理解机器语言,所以任何高级语言的程序想要运行,都必须先将其转化成计算机语言也就是机器码,而转换的方式有两种:

1.编译:在编译型语言的程序执行之前,需要一个专门的编译过程,将源代码编译成机器语言,以后再运行的时候可以直接使用编译结果

2.解释:解释型语言不需要预先编译,其直接将源代码解释成机器码并立即开始执行。

故作为解释型语言的JavaScript是不具有"预编译"阶段的,窃以为称之为"预处理"更加合适。但它究竟叫什么并不重要,重要的是为什么很多同学都认为JS存在"预编译"阶段,到底是JS的哪种行为导致不少同学都认为它产生了"预编译"呢?在此我们提出了疑问

Q:JS是一种解释型语言,所以预编译是子虚乌有的,那么是哪种行为让人们觉得它产生了预编译呢?
A: 因为词法环境和变量提升

词法环境与变量提升

在介绍词法环境之前,我们先看一下V8中JS编译执行过程,大体上可以看成三个阶段(只是大体上看成这三个阶段,实质上JS引擎要复杂的多,现在只是为了说明例子):

1.分词/词法分析阶段:分词是指将代码进行拆分,如var a = 2,将被拆分为var,a,=,2这样的符号;词法分析是指:分析参数,分析变量的声明,分析函数声明(这里将此阶段了解个大概即可,有兴趣请查阅相关书籍,这里不进行过多阐述)

2.解析/语法分析阶段:在分词结束以后,会做代码解析,引擎将 token 解析翻译成一个AST(抽象语法树), 在这一步的时候,如果发现语法错误,就会直接报错不会再往下执行。

3.代码生成阶段:引擎生成CPU可以执行的机器码。 (阅读本文章只需要简要地了解词法分析阶段即可)

在词法分析阶段会创建一个词法环境(Lexical Environment) 的内部(隐藏)的关联对象(有多种翻译,我一般称之为词法环境对象)。

词法环境对象由两部分组成:

1.环境记录(Environment Record) —— 一个存储所有局部变量作为其属性(包括一些其他信息,例如 this 的值)的对象。

2.对外部词法环境 的引用(outer)——与外部代码相关联。

一个变量只是环境记录这个对象的一个属性,对一个变量进行获取或修改相当于是对词法环境对象的一个属性进行获取或修改。

词法环境与我们自己写的代码结构相对应,也就是我们自己代码写成什么样子,词法环境就是什么样子。词法环境是在代码定义的时候决定的,跟代码在哪里调用没有关系。所以说JavaScript采用的是词法作用域(静态作用域)。

下面先给各位同学举个在全局词法环境对象中声明变量的例子:

execution start     //a:<uninitialized>
let a ;             //a:undefined
a=1;                //a:1
a=2                 //a:2

上面的例子为我们展示了在声明变量的情况下(函数声明有些许不同,下文会提到)全局词法环境对象的变化:

1.当脚本开始运行,词法环境预先填充了所有声明的变量。 最初,它们处于“未初始化(Uninitialized)”状态。这是一种特殊的内部状态,这意味着引擎知道变量,但是在用 let 声明前,不能引用它。几乎就像变量不存在一样。

2.然后 let a 定义出现了。它尚未被赋值,因此它的值为 undefined。从这一刻起,我们就可以使用变量了。

3.a被赋予了一个值
4.a被修改了一个值

现在,让我们大声的喊出那句话:‘操作变量实际上是操作词法环境对象的属性。’

函数的声明和变量的声明是有一些差距的,话不多说,上图:

execution start      //a:<uninitialized>,b:function
let a='a';
function b(){
.....
}


我们可以看出变量声明和函数声明的区别在于,变量在被填充的时候处于“未初始化状态”,还不能引用它,但函数在被填充的时候函数初始化会立即完成,函数声明会成为即用型函数

总结

读到这里相信大家应该能理解JS代码执行是解释型语言而非编译型语言了吧,更加清楚对于变量跟函数的预编译阶段的理解了吧。如果对上面不理解的地方,欢迎大家底下留言。记得给小编一个小赞哦!

链接:https://pan.baidu.com/s/1_4PIUb-Yl68aTW9Bw95iJA 
提取码:tnav 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值