javascript中的预解析

js预解析输出结果为了能够更好的理解,简单说一下js作用域的问题

js作用域

js作用域可分为全局作用域(Global)域和局部作用域(Activation)。

全局作用域
全局作用域指的是整个文档,对于js代码来说全局通常是指script标签下为全局作用域;

局部作用域
对于js代码来说,在script标签下进行嵌套的区域称为局部作用域。

总结:在整个文档就相当于全局,全局中如果有嵌套关系的,其嵌套内部就属于局部作用域,有嵌套关系的代码有(函数、对象等)。

var a; //这行a是在script标签下生成的,并不属于script标签下嵌套,所以这个a是属于在全局声明的变量,也称为全局变量
function b() {
	var a = 1; //因函数、对象等具有嵌套作用,所以函数b内部就属于局部作用域,a是在函数b内部声明的,在局部声明的变量就称为局部变量,那么这行a就属于局部变量
}

作用域链

js作用域之间的联系是通过链的形式进行连接的,变量的查找也是从当前作用域依次往全局作用域进行查找。遵循就近原则。这也可以解释为什么同一个名称的变量,分别在不同的作用域下,改变某个变量的值,而不会影响另一个变量(复杂数据类型除外)。

var a = 0;
function b() {
	var a = 1;
	console.log(a);//因为当前作用域有变量a,所以结果就是b函数中a的值
}
b();

------------------------------------------------------------------------------------------

var a = 0
function b() {
	console.log(a);//因为当前作用域中没有a变量,所以上一级作用域就是全局,于是结果就是全局a的值
}
b();

js预解析

js执行步骤
js是解释型语言,在执行代码时是解释一行执行一行。但j浏览器引擎在执行js代码之前要做两件事,总共是三件,通常被称为js三部曲:

  1. 先通篇扫描一遍,看看有没有低级的语法错误,若有则直接报错;
  2. 然后再进行预解析;
  3. 最后解释并执行代码;

预解析
预解析是在代码执行之前发生的。预解析时引擎会以以下原则处理代码:
预解析四部曲

  1. 先创建一个对象根据全局作用域或局部作用域而定,全局创建GO对象、局部创建AO对象;(这里的GO相当于全局对象window,在这里就不详细介绍了)
  2. 将代码中(函数的)形参 、变量声明中的形参名和变量名作为AO或GO的属性名,值为undefined;
  3. 将实参值赋予形参;
  4. 在函数体里找函数声明,将函数名作为AO或GO的属性名,值为函数;

注意:在同一个作用域下不可能出现两个相同的变量名/属性名,所以AO和GO对象中的属性名只有一个,在解析过程中如有重复属性名则不会重新创建新的属性名,值会覆盖原有的属性名的值。

示例

a(0);
var a = 1;
function a(a) {
	console.log(a);
	var a = 11;
	function b() {
		a = 111;
	}
	console.log(a);
	console.log(b);
	var b = 1;
	console.log(b);	
}
console.log(a);
//a();

在这段代码中打印的a和b都为多少?
我们来分析一下:
先看全局作用域:

先创建一个GO对象:

GO {
	
}

按照四部曲第二部,GO对象就变成了:

GO { 			         GO {                      	   GO {
a: undefined,--第四部-->a: function a() {....} , --顺序执行-->a: 1,
}				        }                             }

再看局部作用域:

先创建一个AO对象:

AO {

}

根据四部曲第二部:

AO {
	a: undefined,-顺序执行->(赋值)->a: 0,-变量赋值->a: 11,
	
	b: undefined,-第四部->b: function b() {},-变量赋值->b: 1,
}

在这里我说明一下上面写的大致的意思:
js引擎收到代码后通篇扫描后进行预解析。当js读第一行的时候他会创建一个GO对象,引擎会把变量声明和函数声明中的名作为GO对象的属性名并赋值为undefined,在全局作用域中有一个变量a和一个函数a,所以将函数赋值后全局中预解析基本完成了,所以预解析完成全局a的值是函数a( function a() {} ),预解析在全局解析完后就看局部的。
在局部作用域中,先将形参和变量名(变量声明)作为AO对象中的属性名并赋值为undefined,然后是实参值赋予形参、函数赋值等完成预解析。相当于形成了一下代码:

	var a; //全局(GO)下的a
	function a(a) {
		var a; //局部(函数a)(AO)下的a
		var b; //局部(函数a)(AO)下的b
		a = 0; //局部(函数a)(AO)下的 a = 0
		console.log(a); //打印的是局部(函数a)的(AO)中的a
		a = 11; //局部(函数a)(AO)中的 a = 11
		function b() { //局部(函数a)(AO)中的 b = function b() {}
			a = 111; //局部(函数a)(AO)中的 a = 111
		}
		console.log(a); //打印的是局部(函数a)的(AO)中的a
		console.log(b);//打印的是局部(函数a)的(AO)中的b
		b = 1; //局部(函数a)(AO)中的 b = function b() {}
		console.log(b);	//打印的是局部(函数a)的(AO)中的b
	}
	a(0); //全局(GO)下a函数执行
	a = 1; //全局(GO)下的 a = 1
	console.log(a); //打印的是全局(函数a)的(GO)中的a
	//a();

然后js代码在解释一行执行一行,所以最后输出的结果是在这里插入图片描述
在代码中最后有一个被注释掉的a();调用函数,如果把调用函数写在最后面会报错。由下图片中输出的值可看出:
(换张图好看点)
在这里插入图片描述
最后a输出的是一个数字1而非函数,所以在最后一行调用函数会报错。
还有个问题就是代码中函数b是不执行的 因为没有调用函数b();,所以a = 111;也不会执行,因此最后a输出的是11,而非111。

本人知识水平有限,文章中如有错误还请见谅,也欢迎大家能积极指出错误,我们共同进步!!!文章中描述如有疑惑也可私信我,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海阔,天空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值