JavaScript预编译(执行期上下文)总结

预编译(又叫“执行期上下文”)

一般来说,预编译与闭包、作用域链和闭包是密切相关的,好多人包括在企业开发的人都听说过一句话叫做“函数声明整体提升”。这个就是预编译后的一个小结果,所以今天自己总结了一下。分为以下几个步骤来说。

大家先看看这段代码

console.log(a);
var a = 1;

结果:
JavaScript预编译(执行期上下文)总结
为什么变量的声明在输出的下面,却没有报错?值为什么是undefined?

大家再看看下面这段代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
<script>
	function test(a,b){
		console.log(a);
		var a = 'demo';
		console.log(a);
		function a(){}
		console.log(a);
		var a = function (){}
		console.log(a);
		console.log(b)
		var b = 1;
	}
	test(1);
</script>
</body>
</html>

大家看到这段代码是不是很震惊呢?形参、变量名、函数名都是“a”,那么输出的结果会是怎样呢?
JavaScript预编译(执行期上下文)总结
和大家想的一样吗?大家心里是不是有这么几个问题,前四个输出的都是a,为什么输出的结果不一样呢?而且b变量不是把1赋值给它了吗,为什么会是undefined?接下来咱们来讲讲什么是预编译(执行期上下文)。到最后大家就明白了。

预编译(‘执行期上下文’)

预编译发生在函数执行之前。划重点了啊!!!!! 这句话很重要,函数执行之也就是在这段程序开始之前,浏览器对马上要执行的函数进行预编译!!
预编译四部曲

  1. 创建AO对象
  2. 找形参和变量声明,将变量和形参作为AO属性名,值为undefined
  3. 将实参和形参相统一
  4. 在函数体里找到函数声明,值赋予函数体
    最后程序输出变量值的时候,就是从AO对象中拿。

以第一个问题为例咱们开始讲解。以下过程都是在系统内部完成的

1、创建AO对象

var  AO = {
		
}

2、形参和变量声明,将变量和形参作为AO属性名,值为undefined
这里的形参首先出现的是a,b。变量为a,b。
大家同时也要区分开函数声明和表达式。function demo(){}这个叫做函数声明,var demo = function (){}是表达式。它是由两部分组成,var demo 变量声明。demo = function(){}变量赋值。 同理 var demo = ‘aaa’ 也是一样的。这里说的是找变量。

var AO = {
		a = undefined;
		b = undefined;
}

3、将实参和形参相统一
这里的实参只有一个是1。

var AO = {
		a =1;
		b = undefined;
}

4、在函数体里找到函数声明,值赋予函数体
这里只有第十三行是函数声明,第十五行不是。上面已经讲过了。

var AO = {
		a = function a(){};
		b = undefined;
}

到此为止预编译结束。然后调用函数,系统执行程序。
5、系统执行程序(解释一行执行一行)

  1. console.log(a),输出a。这是输出的值为function a(){}
  2. var a = ‘demo’ 其实就是a = ‘demo’。因为var a已经在预编译中ok了。AO中的a的值变为’demo’;
  3. console.log(a) ,这时候输出的就是 demo
  4. function a(){} 在预编译中已经用过了就不用了。
  5. console.log(a) , 输出 demo
  6. var a = function (){} AO中的a的值变为function (){};
  7. console.log(a),输出 function (){}
  8. console.log(b) b中的值一直未undefined ;输出 undefined
  9. var b = 1; 将AO对象中的b的值变为1;
这样就解释了刚开始提出的两个问题。这种作用在全局中也是可以的,预编译的作用域为全局的变量时,创建的AO对象变为GO对象,相当于省略了第三步。其他的都一样。

如果你喜欢记得转载和点赞哦,欢迎留言评论!!!
接下来我会为大家分享作用域、作用域链和闭包的知识。