關(guān)于編譯器,引擎會在解釋 JS 代碼之前首先對其進行編譯精绎。編譯階段的一部分工作就是找到所有的聲明速缨,并用合適的作用域?qū)⑺鼈冴P(guān)聯(lián)起來。
1.聲明提升
“提升”就是變量和函數(shù)聲明從它們在代碼中出現(xiàn)的位置被“移動”到了最上面代乃,這個過程就叫“提升”旬牲。
// 代碼示例 1
foo();
function foo() {
console.log(a); // undefined
var a = 2;
}
如上面代碼示例 1, foo
函數(shù)的聲明被提升了搁吓,因此第一行中的調(diào)用可以正常執(zhí)行引谜。需要注意的是,每個作用域都會進行提升操作擎浴。也就是函數(shù)自身也會在內(nèi)部對 var a 進行提升,所以最終的形式可以理解為如下代碼示例 2:
// 代碼示例 2
function foo() {
var a;
console.log(a); // undefined
a = 2;
}
foo();
2.函數(shù)表達式不會被提升
// 代碼示例 3
foo(); // TypeError 類型錯誤
var foo = function bar() {
// ...
}
foo()
由于對 undefined 值進行函數(shù)調(diào)用而導(dǎo)致非法操作毒涧,因此拋 TypeError 出異常贮预。
3.函數(shù)優(yōu)先
函數(shù)聲明會被提升到普陀變量之前。
// 代碼示例 4
foo(); // 1
var foo;
function foo() {
console.log(1);
}
foo = function() {
console.log(2);
}
上述代碼示例 4 會被引擎理解為如下形式:
function foo() {
console.log(1);
}
foo(); // 1
foo = function() {
console.log(2);
}
重復(fù)的函數(shù)聲明可以覆蓋前面的契讲。
盡可能避免在塊內(nèi)部聲明函數(shù)仿吞。
總結(jié)
-
var a = 2;
其中var a;
是編譯階段的任務(wù),a = 2;
是執(zhí)行階段的任務(wù)捡偏; - 所有的聲明(變量和函數(shù))都會被“移動”到各自作用域的最頂端唤冈,這個過程叫“提升”;
- 聲明本身會被提升银伟,而包含函數(shù)表達式在內(nèi)的賦值操作不會被提升你虹;
- 避免重復(fù)聲明。
注:文章參考總結(jié)自 《你不知道的 JavaScript 上卷》[美] KYLE SIMPSON 著 第 42 頁彤避。