文章目錄
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
