JavaScript 預(yù)編譯過程的詳細(xì)解讀

文章目錄

JavaScript運(yùn)行三部曲

JavaScript預(yù)編譯

01 關(guān)于預(yù)編譯的一些知識點(diǎn)

02 預(yù)編譯四部曲(局部)

1. 創(chuàng)建AO對象(Activation Object) (執(zhí)行期上下文)

2. 找形參和變量聲明,將變量和形參名作為AO屬性名,值為undefined

3. 將實(shí)參值和形參統(tǒng)一 (全局預(yù)編譯省略這一步)

4. 在函數(shù)體里面找函數(shù)聲明,值賦予函數(shù)體

03 綜合例題------全局和局部的預(yù)編譯和解釋執(zhí)行過程

1. 全局預(yù)編譯三部曲

2. 局部預(yù)編譯四部曲

3. JavaScript的解釋執(zhí)行

JavaScript運(yùn)行三部曲

在學(xué)習(xí)預(yù)編譯之前,我們要先了解一下js的運(yùn)行步驟:

語法分析:通篇檢查代碼是否有語法錯誤,若有,則程序不會執(zhí)行;若無,則進(jìn)行預(yù)編譯。

預(yù)編譯

解釋執(zhí)行:從上到下依次執(zhí)行函數(shù)代碼。

JavaScript預(yù)編譯

01 關(guān)于預(yù)編譯的一些知識點(diǎn)

(1)函數(shù)聲明整體提升:不管你的函數(shù)聲明寫在哪里,系統(tǒng)總是會將其提升到邏輯最前面,所以不管你是在函數(shù)的上面或下面調(diào)用函數(shù),其實(shí)都是在下面調(diào)用的。(2)變量僅聲明提升:如 var a = 123;則將其拆成兩個(gè)部分 即 聲明var a位置提升到邏輯最前端,賦值a=123不提升。所以若是在聲明賦值變量前進(jìn)行調(diào)用,則會顯示undefined,而不會報(bào)錯。(3)imply global 暗示全局變量:即任何變量,如果變量未經(jīng)聲明就賦值,此變量就為全局對象所有。即:

function test(){

a = 10; //在局部里面賦值,沒有進(jìn)行var聲明

}

因?yàn)闆]有進(jìn)行var聲明,相當(dāng)于在全局域里定義,即window.a = 10;

var a = b = 123;//局部里

上面代碼的執(zhí)行順序:先將123賦給b,其次是b的值賦給a,但是聲明只聲明了a,沒有聲明b,所以此時(shí)b歸window所有。

(4)一切聲明的全局變量,全是window的屬性,即歸window所有,而調(diào)用全局變量,其實(shí)就是調(diào)用window.變量。(window 就是全局的域)即:

var b = 234; //在全局域里面聲明定義

即 相當(dāng)于window.b = 234。

02 預(yù)編譯四部曲(局部)

下面就通過check這個(gè)函數(shù)來解釋預(yù)編譯的四個(gè)步驟

function check(a) {

console.log(a);

var a = 123; //變量聲明和定義

console.log(a);

function a() {} //函數(shù)聲明

console.log(a);

var b = function () {} //變量聲明和定義

console.log(b);

function d() {} //函數(shù)聲明

}

check(1);

1. 創(chuàng)建AO對象(Activation Object) (執(zhí)行期上下文)

? AO {}

2. 找形參和變量聲明,將變量和形參名作為AO屬性名,值為undefined

從上面的代碼中,我們可以知道形參是a,也定義了變量b。

AO {

a : undefined,

b : undefined,

}

3. 將實(shí)參值和形參統(tǒng)一 (全局預(yù)編譯省略這一步)

函數(shù)執(zhí)行傳入的實(shí)參是1,所以形參a=1。

AO {

a : 1,

b : undefined,

}

4. 在函數(shù)體里面找函數(shù)聲明,值賦予函數(shù)體

a的值變成了函數(shù)體(存在同名的情況,直接覆蓋以前的值),還添加了一個(gè)d屬性,值為函數(shù)體。

AO {

a : function a() {},

b : undefined,

d : function d() {}

}

以上預(yù)編譯過程就結(jié)束了,接下來就是js三步曲中的第三步------解釋執(zhí)行。(解釋執(zhí)行的時(shí)候,AO對象里的屬性值也會發(fā)生改變,而每次想要輸出的變量,其實(shí)就是在AO對象中找對應(yīng)的值)

//開始js的解釋執(zhí)行,修改AO對象

function check(a) {

// 此時(shí)的AO對象就是預(yù)編譯結(jié)束之后的樣子

? ? // AO {

? ? // a : function a() {},

? ? // b : undefined,

? ? // d : function d() {}

? ? // }

? ? console.log(a); //輸出function a() {}

? ? var a = 123; //預(yù)編譯已經(jīng)將var a提升執(zhí)行過了,所以直接執(zhí)行賦值a=123

? ? // AO {

? ? // a : 123,

? ? // b : undefined,

? ? // d : function d() {}

? ? // }


? ? console.log(a); //輸出123

? ? function a() {} //預(yù)編譯已經(jīng)提升聲明了,被優(yōu)先執(zhí)行了,所以不看了

? ? console.log(a); //輸出123

? ? var b = function () {} //預(yù)編譯已經(jīng)將變量b的聲明提升執(zhí)行了,所以只用看賦值

? ? // AO {

? ? // a : 123,

? ? // b : function() {},

? ? // d : function d() {}

? ? // }


? ? console.log(b); //輸出function() {}


? ? function d() {} //預(yù)編譯已經(jīng)提升聲明了,被優(yōu)先執(zhí)行了,所以不看了

}

check(1); //函數(shù)執(zhí)行,實(shí)參為1

03 綜合例題------全局和局部的預(yù)編譯和解釋執(zhí)行過程

現(xiàn)在就通過下面的代碼來練習(xí)一下全局和局部一起的預(yù)編譯和它們的執(zhí)行過程:

console.log(test);

function test(test) {

? ? ? ? ? ? console.log(test);

? ? ? ? ? ? var test = 234;

? ? ? ? ? ? console.log(test);

function test() { }

}

test(1);

var test = 123;

1. 全局預(yù)編譯三部曲

(1)創(chuàng)建GO對象:全局預(yù)編譯的情況下,會生成Global Object對象,其實(shí)和AO同理,只是換了個(gè)名字。(GO === window)

GO {}

(2)找變量聲明作為GO屬性名,值為undefined

GO {

test : undefined

}

(3)找函數(shù)聲明,值賦予函數(shù)體

GO {

test : function test(test) {...}

}

2. 局部預(yù)編譯四部曲

(此時(shí)的AO對象為函數(shù)test里的)

(1)創(chuàng)建AO對象

AO {}

(2)找形參和變量聲明賦值undefined

AO {

test : undefined

}

(3)實(shí)參形參統(tǒng)一

AO {

test: 1

}

(4)找函數(shù)聲明,值賦予函數(shù)體

AO {

test: function test() {}

}

123

3. JavaScript的解釋執(zhí)行

// js開始解釋執(zhí)行

//全局

// GO {

// test : function test(test) {...}

// }

console.log(test); // function test(test) {...}

function test(test) {

// 局部

// AO {

// test: function test() {}

// }

console.log(test); // function test(){}

var test = 234;

// AO {

// test: 234

// }

console.log(test); // 234

function test() {}//預(yù)編譯已經(jīng)提升了聲明,被優(yōu)先執(zhí)行了,所以不看了

}

test(1);

var test = 123;

// GO {

// test : 123

// }

console.log(test);? //123

// js執(zhí)行結(jié)束

注意:如果GO中和AO中都有test函數(shù),若在局部中就先找AO的,但如果AO沒有的話再找GO;若在全局中就找GO的用。(就近找,自己沒有找爸爸,爸爸沒有找爺爺?shù)龋?/p>

個(gè)人筆記,歡迎大家交流探討!

百度網(wǎng)盤鏈接:https://pan.baidu.com/s/1vF1A7beP0oovDaUFvjY9MA?提取碼:?r5d3

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容