提升
這里我們不考慮 ES6 這部分的知識點
前期知識準(zhǔn)備
1、首先先理解 JavaScript 是如何執(zhí)行代碼的
JavaScript 是動態(tài)語言瑟押,在執(zhí)行代碼時要先進(jìn)行編譯枷颊。
第一部分是編譯代碼(主要是全局聲明函數(shù)和變量)生音,并且生成代碼(將用戶的代碼生成符合 JavaScript 正確順序執(zhí)行久妆,具體順序后面有細(xì)講)
第二部分是執(zhí)行代碼(執(zhí)行函數(shù)或變量賦值)
2脉让、了解 JavaScript 中的 引擎桂敛、編譯器、作用域三者的作用及區(qū)別
- 引擎:從頭到尾負(fù)責(zé)整個 JavaScript 程序的編譯及執(zhí)行過程溅潜。
- 編譯器:負(fù)責(zé)語法分析及代碼生成
- 作用域:負(fù)責(zé)收集并維護(hù)有所有聲明的標(biāo)識符(變量)組成的一系列查詢埠啃,并實施非常嚴(yán)格的規(guī)則,確定當(dāng)前執(zhí)行的代碼對這些標(biāo)識符的訪問權(quán)限伟恶。
<img src="https://i.loli.net/2021/09/19/DV8ivWMm7hB1Jfr.png" style="zoom:80%;" />
上才藝
// 調(diào)用函數(shù)
fun1();
// 聲明全局變量
var g = 2;
// 函數(shù)聲明
function fun1() {
console.log(b);
var b = 0;
console.log(b);
console.log(g);
}
-
補充:
局部作用域 指的是函數(shù)內(nèi)部(函數(shù)分很多種碴开,這里是所有函數(shù))
var b =2 在程序中是被拆分成 var b b =2
-
函數(shù)聲明的優(yōu)先級要高于變量
var a = 10; function a() {} console.log(typeof a) // number
函數(shù)可以分為函數(shù)聲明,函數(shù)表達(dá)式博秫,立即執(zhí)行函數(shù)等潦牛,但唯獨函數(shù)聲明會提升。
-
第一步:程序會被轉(zhuǎn)成 JavaScript 內(nèi)部認(rèn)為正確的順序
function fun1() { var b; console.log(b); // undefined b = 0; console.log(b); // 0 console.log(g); // undefined } var g; fun1(); g = 2;
-
依據(jù)以下幾點來判斷其順序
- 從上往下(全局)看:看到變量聲明或函數(shù)表達(dá)式時將其提到最前面挡育。且函數(shù)聲明的優(yōu)先級要高于變量(可以理解為在當(dāng)前作用域中函數(shù)表達(dá)式始終是在最前面的)
- 接下來就是調(diào)整局部作用域中的函數(shù)表達(dá)式和變量聲明巴碗,依據(jù)跟上面一樣。
-
第二步:將全局及局部變量和函數(shù)告訴作用域即寒,作用域會根據(jù)信息給變量和函數(shù)創(chuàng)建相對應(yīng)的空間
-
如何創(chuàng)建依據(jù)以下幾點
- 前提:變量和函數(shù)在全局下橡淆。直接在頂級作用域聲明變量和函數(shù)
- 局部(函數(shù))下:在局部作用域下聲明變量和函數(shù)。
-
- 第三步:代碼執(zhí)行階段母赵,就是按第一步生成的順序從上到下來執(zhí)行逸爵。
在上面的小例子中,在 JavaScript 執(zhí)行被我分為三部分凹嘲。真正執(zhí)行是倆部分(編譯階段和執(zhí)行階段)师倔,只不過在編譯階段要經(jīng)歷第一步和第二步。為了方便理解周蹭,我把它細(xì)分出來趋艘。
執(zhí)行階段
具體看下面代碼
(function() {
var a = b = 5;
})()
console.log(b);
console.log(a);
根據(jù)上面的例子疲恢,很容易可以得到真正的執(zhí)行順序
(function() {
var a;
a = b;
b = 5;
})();
console.log(b); // 5
console.log(a); // Uncaughte ReferenceError: a is not defined
這里跟第一個案例的區(qū)別在于執(zhí)行階段
在 a = b 賦值階段,首先
- 引擎會問作用域在立即執(zhí)行函數(shù)中是否存在 變量 b 瓷胧;
- 作用域在該作用域(立即執(zhí)行函數(shù))下找變量 b显拳,若沒有找到。此時作用域會接著往上一層作用域找變量 b 直到找到頂級作用域還沒有找到搓萧,直接告訴引擎編譯器沒有聲明該變量萎攒。
- 引擎接收到信息后,執(zhí)行 a = b 由于程序中并沒有存在變量 b , 故執(zhí)行 console.log(a); 會報錯 Uncaughte ReferenceError: a is not defined
在 b = 5 這個階段跟上面是不一樣矛绘,在賦值前變量已經(jīng)被創(chuàng)建了耍休,只不過是在全局下聲明,故在 console.log(b) 輸出結(jié)果為 5
這里就涉及到 RHS 和 LHS 具體看 這里