對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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章