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

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

众所周知,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(){
.....
}


复制代码

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

致歉

后面被我删掉了写的太乱了…..

上面的两个小图片应该能够让同学们对词法环境对象有个浅显的了解,当然,我在举变量声明的例子的时候,仅仅是举了let声明的例子,但用var声明和与let声明还是有些不同之处的。这个就先不写了,毕竟只是快速地对词法环境对象有个浅显的了解,如果后面我还有兴趣的话可能会写一下let声明与var声明在词法环境对象内有何不同(这个比较简单,可以做个demo到时候给大家演示,这篇文章不写的原因是:这是我写的第一篇文章,没什么写的经验,就感觉自己的文笔很差,思维逻辑较为混乱,整体布局也不明确,写到这实在是写不下去了,等下次写之前应该先整理一下自己的思路,不能像这次一样,直接动手开写)

如果同学们都看到这里了,那就先不要划走,帮忙点个赞吧,给点鼓励吧

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享