对JS预编译过程的粗浅理解

变量提升声明,不提升赋值

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

输出结果undefined,是因为把变量声明提升到了顶部,等价于如下代码:

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

函数整体提升

fun();// 1
function fun(){
	console.log(1);
};

输出结果是1,因为把整个函数都提升到了顶部,等价于如下代码:

function fun(){
	console.log(1);
};
fun();// 1

深入理解真正的预编译

预编译的过程:

1、创建VO(变量对象 Variable Object)或AO(活动对象 Activation Object)。
2、找形参和变量声明,将变量和形参名作为AO属性名,值为undefined。
3、将实参值和形参统一,实参的值赋给形参。
4、在函数体里面找函数声明,值赋予函数体。

	fun(a,b,3);
	function fun(a,b,c){
		console.log(a);
		console.log(b);
		console.log(c);
		console.log(d);
		console.log(e);
		function d(){};
		var e=function(){};
		console.log("—————我是分割线—————");
		console.log(a);
		console.log(b);
		console.log(c);
		console.log(d);
		console.log(e);
	}
	function b(){};
	var a=1;

输出结果:
预编译输出结果
接下来进行分析,建议扣出上面的代码,对照着看,那我们开始飙车了—>

1、首先系统自动创建变量对象VO={};:

	VO={}

2、然后函数和变量提升声明:

	VO={
		a:undefined
		b:undefined
		fun:undefined
	}

3、然后函数赋值提升:

	VO={
		a:undefined
		b:function b(){}
		fun:function fun(){}
	}

4、然后执行fun(a,b,3);,将AO中的a、b以及常量3传递给fun(),等价于如下代码:

	fun(undefined,function b(){},3)
	function fun(a,b,c){...}

5、我们继续分析,在fun()中,又会创建一个活动对象AO={};并且提升函数和变量的声明:

	AO={
		a:undefined
		b:undefined
		c:undefined
		d:undefined
		e:undefined
	}

6、在函数体中,会将实参值和形参统一,也就是将实参的值赋给形参:

	AO={
		a:undefined
		b:function b(){}
		c:3
		d:undefined
		e:undefined
	}

7、然后函数赋值提升,在函数体里面找函数声明,值赋予函数体:

	AO={
		a:undefined
		b:function b(){}
		c:3
		d:function d(){}
		e:undefined
	}
注意:d与e的区别!

8、接下来执行完第一波console.log();后,再将AO中e的值改变为匿名函数:

	AO={
		a:undefined
		b:function b(){}
		c:3
		d:function d(){}
		e:function (){}
	}

9、再执行第二波console.log();就完事了
预编译输出结果

——————————2019年7月4日——————————
今天突发奇想,要是在fun()中重新声明函数b,结果会是怎样?

	fun(a,b,3);
	function fun(a,b,c){
		console.log(a);
		console.log(b);
		console.log(c);
		console.log(d);
		console.log(e);
		function b(){console.log('new')}
		function d(){};
		var e=function(){};
		console.log("—————我是分割线—————");
		console.log(a);
		console.log(b);
		console.log(c);
		console.log(d);
		console.log(e);
	}
	function b(){console.log('old')};
	var a=1;

这里就得补上一个知识点,函数声明提升>形参提升>变量提升
所以新声明的b(){console.log('new')}会替换掉AO中原本的形参b(){console.log('old')}

这里再写一个经典:

var name = 'xiaoxiao';
function fun() {
     alert(name);
     var name = 'dada';
     alert(name);
     alert(age);
}
fun();

猜猜答案是什么?

发布了51 篇原创文章 · 获赞 69 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章