前言:
今天各位老铁们对“预编译有哪些”大致比较着重,同学们都需要剖析一些“预编译有哪些”的相关内容。那么小编在网摘上汇集了一些有关“预编译有哪些””的相关资讯,希望各位老铁们能喜欢,你们快快来了解一下吧!前言
许多同学在学习js的基础时,学到很多调用api的方法,觉得这些东西是最重要的,认为js中只要知道怎么使用一些函数,知道如何调用api,这样就能算是精通掌握js了,但其实这可能连入门都不算,js中底层的编译原理是很重要的,以下这几个例子能够明显地感受出来,我们将通过几个例子感受和学习js中的预编译底层原理,那我们首先应该了解下预编译的概念是什么。
概念--->预编译
js中的预编译是指在代码被执行前解释器对代码进行的操作,主要有两个操作,第一是变量声明,第二是函数声明,为什么会进行这两项操作,是为了确保在代码执行时,未被声明的变量能够被提前使用。
Example One
二、请看这下面这段代码:
有人会说:还会有人写出这种代码吗?这不是一眼错?编译器肯定会报错的..
但是事实是:编译器并不会报错,只是会输出undefined,那么有小伙伴就奇怪了,为什么定义变量在输出之后,却不会报错。这就是js在预编译中进行的操作:声明提升
声明提升
声明提升包括两种,一种是变量声明,另一种是函数声明
变量声明:是将声明提升,让变量提前声明,也就是在代码执行前告诉编译器有一个叫做a的变量。
函数声明:同理,函数声明是将整个函数体提前声明,让编译器知道有一个存在的函数体。
所以编译器并不会报错,而是输出undefined的原因是,解释器将变量的声明提升,相当于是在代码的第一行定义了一个变量a,只不过没赋值。
Next Example....
Example Two
在这个例子中我们将细化了解预编译中要进行的操作,例子如下:
通过对fn这个函数的调用,一共会输出三个数值,那么你觉得输出的三个数值是哪三个?两分钟思考时间...
3
2
1
时间到....
答案是
①function:a
②2
③2
那有的同学就会问了,为什么第一个输出不是传入的实参1呢,为什么第三个不是function:b呢?这里就要讲到js预编译中的操作顺序问题了
预编译中的底层操作
在函数体中,预编译大体有四步
1、创建函数的执行上下文对象 AO(Activation Object)
2、找形参和变量声明,将形参和变量名作为AO的属性,值为undefined
3、将实参和形参统一
4、在函数体内找函数声明,将函数名作为AO的属性名,值赋予函数体
在全局变量中,预编译的步骤会更简单一些
1.创建全局执行上下文对象 GO(Global Object)
2.找变量声明,变量名作为GO的属性名,值为undefined
3.在全局找函数声明,函数名作为GO的属性名,值为函数体
Example Three
第三个例子我们要聊的是在函数体中预编译时调用变量时的先后顺序
聪明的朋友们,这两个输出应该是什么呢?
①undefined②200
对啦!果然没看错你们! 在所以这为什么第一个输出是undefined呢,是因为我们前面讲到的声明提前,而在js中,函数体会先调函数体内是否有global这个变量,没有的话才会调用全局变量。如果将第6行的代码删去的话,第一个输出就会是100了,而不是undefined,这就是因为在函数体内没有声明变量,从而会从全局变量中查询global,而global在全局变量中已经被赋值了100.
小结
通过这几个案例,相信各位聪明的小伙伴不仅都了解js中预编译的基本概念,也能体会到底层的逻辑机制能够对代码的流程起到很深刻的作用,预编译作为JavaScript运行机制的核心一环,通过变量声明提升与函数声明提升,确保了代码在执行时能够访问到所有已声明的标识符,即便它们出现在实际声明之前,这一机制体现了JavaScript的变量提升(hoisting)概念,但是还需要注意一点,let和const声明的变量虽然在逻辑上被提升,实际上在赋值前处于临时死区(TDZ),无法访问。
在函数体内,预编译包括创建AO、处理形参和变量声明、实参与形参的绑定、函数声明的处理。全局上下文的预编译则涉及GO的创建、变量声明处理、函数声明处理。
总之,JavaScript中预编译机制不仅仅只是一种机制,更是深入理解代码运行机制和优化代码流程的关键。通过掌握预编译原理,我们就能更精准地控制代码执行的流程,提升程序的可读性和稳定性。
作者:cc的牛奶ovo
链接:
标签: #预编译有哪些