我們先提前預告一下變量提升的幾個要點,然后在根據(jù)后面的例子進一步闡述:
- 變量提升是按照作用域為單位的;
- 函數(shù)的提升優(yōu)先于變量的提升;
- 存在多個相同函數(shù)名的函數(shù)會被覆蓋;
- 函數(shù)表達式并不會被提升。
章節(jié)直通車:
什么是變量提升
可能有些小伙伴不清楚什么是變量提升,我們以一個簡單的例子來說明一下:
console.log( a );
var a = 2;
大家可以自己思考或者直接試驗一下,這里打印的a為undefined。
我們在第一章中說道編譯器的基礎三步驟,其一就是分詞、詞法分析,在此階段編譯器會把一些變量和相應的作用域進行關聯(lián),在作用域中提前聲明,我們可以把上面的代碼稍微變動如下:
編譯階段:
var a;
執(zhí)行階段:
console.log( a );
a = 2;
所以這時的a已經(jīng)被定義,輸出的時候就是undefined。這個就叫做變量提升。
變量提升是按照作用域為單位的
foo();
function foo() {
console.log( a ); // undefined
var a = 2;
}
在全局作用域中,foo函數(shù)被提升;
在foo函數(shù)中,變量a被提升。
console.log(c); // undefined
if (true) {
var c = 1;
}
注意,if的大括號并不是作用域,所以這里的作用域還是全局作用域,變量c被提升了。(上一章節(jié)有具體介紹JavaScript作用域)
本來準備按照《你不知道的JavaScript》書中以if大括號和函數(shù)為例來說明,但是現(xiàn)在es6已經(jīng)改變了這種做法,在if條件中的函數(shù)會默認為函數(shù)表達式,函數(shù)表達式并不會被提升如下:
foo(); // "b"
var a = true;
if (a) {
function foo() { console.log( "a" ); }
}
else {
function foo() { console.log( "b" ); }
}
現(xiàn)在這里已經(jīng)不像書中說的輸出“b”了,而是undefined。
當然對于老版本這種操作也是非常不友好的,并不推薦使用,這里只是提一嘴。
函數(shù)的提升優(yōu)先于變量的提升
foo(); // 1
var foo;
function foo() {
console.log( 1 );
}
foo = function() {
console.log( 2 );
};
上面很清晰的可以看到函數(shù)foo的聲明是優(yōu)先于變量的,否則會報錯TypeError。我們可以將上面的代碼修改為提升后的樣子:
function foo() {
console.log( 1 );
}
// var foo; 由于上面foo已經(jīng)被聲明了,這一條就被直接過濾了
foo(); // 1
foo = function() {
console.log( 2 );
};
存在多個相同函數(shù)名的函數(shù)會被覆蓋
foo(); // 3
function foo() {
console.log( 1 );
}
var foo = function() {
console.log( 2 );
};
function foo() {
console.log( 3 );
}