通过简单的三行代码,来透彻理解JavaScript预解析,真的可以实现吗?
通过简单的三行代码,来透彻理解JavaScript预解析,真的可以实现吗?
01先看这三行代码
请问以下三行代码中,打印的结果是?
如果对JavaScript预解析没有接触过,或者不清楚变量声明提升和函数声明提升的相关概念,很可能会得出这样的结论。
以上代码打印结果为:function a() {},但是最终的打印结果是:10。
为什么打印10而不是function a() {}呢?这里就需要JavaScript预解析的机制了。
02JavaScript预解析
JavaScript引擎会在代码执行前对JavaScript代码进行预解析(预编译),所谓的预解析其实就是把代码中用var声明(定义)的变量和函数体(例如:function(){})进行提前的声明提升。
变量声明提升
如下代码:
var a = 10;这样的变量声明,会被分解成两个独立的步骤:
以上其实就是JavaScript引擎对JavaScript代码预解析的过程,也是变量声明提升的过程。
预解析完毕之后,JavaScript引擎才会按照预解析后的代码逐行进行执行,很显然上面代码打印的最终结果是 10。
注意console.log(a)不会参与到预解析过程中,所以console.log(a)不会提升,预解析的过程只是涉及到变量声明提升和函数声明提升。
通过上面的代码,我们可以得出一个结论:变量声明提升,只提升声明,而不会提升赋值
函数声明提升
如下代码:
function a(){}这样的函数声明,会把函数声明提升到当前 作用域的最前面,注意是最前面。
对,你没有看错,是最前面,所以这里也有一个结论:函数声明提升优先于变量声明提升。
提升后如下所示:
所以根据以上的预解析,然后再逐行执行代码,最后结果打印为10(到这里就解释了为什么一开始上面打印10而不是function a() {}的问题了)。
注意:函数表达式和函声明是有区别的,函数表达式提升不会跟函数声明提升一样,它跟变量声明提升是一样的(只提升声明,不会提升赋值)
区分函数声明和表达式最简单的方法是看 function 关键字出现在声明中的位置(不仅仅是一行代码,而是整个声明中的位置),如果 function 是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式。
小结
◻ JavaScript预解析就是先对函数声明和变量声明进行提升(提升完之后,在逐行执行代码)
◻ 变量声明提升会提升声明,但不提升赋值
◻ 函数声明提升优先于变量声明提升(注意这里不是函数表达式哈)
◻ 函数声明和函数表达式之间最重要的区别是它们的名称标识符的位置(function是声明第一个词就是函数声明,否则就是函数表达式)
03再看这三行代码
让我们再看看这三行代码(顺序不一样了哦)
我们知道了什么是JavaScript预解析(变量声明提升和函数声明 提升),可以再看如下代码,请说出打印的结果是?
思考……,按照上面的预解析,很多人得出的结果是 undefined,但是实际执行代码之后 ,最终结果是function a(){}。
为什么?
我们一起再来看看,以上三行代码预解析是怎样的,执行过程中发生了什么事情?
上述代码按照JavaScript预解析的机制,预解析代码如下所示:
根据以上的预解析之后的代码,很多人一致认为结果就是 undefined(因为 var a 的默认值是undefined,所以打印的结果是 undefined)。
但是当我们执行以上的预解析代码之后,最终结果仍然是 function a(){}。
所以肯定是在执行过程中发生了一些事情,并不是预编译的机制出现问题了。
代码执行过程分析(需要跟着我的思路走哦):
至此,以上我们就清晰的理解了,为什么以下这三行代码执行的结果是 function a(){}。
04总结
1️⃣ JavaScript预解析就是先对函数声明和变量声明进行提升(提升完之后,在逐行执行代码);
2️⃣ 变量声明提升会提升声明,但不提升赋值;
3️⃣ 函数声明提升优先于变量声明提升;
4️⃣ 重复声明的变量在执行过程中会被忽略掉 ,不会执行。