javascript(以下稱js)中的變量提升是我們經(jīng)常會(huì)遇到的問題怀骤。
變量提升砸脊,顧名思義就是將后面的變量提升至作用域頂端笙以。
說到這里可能你需要了解下作用域是什么感挥,我會(huì)在有時(shí)間時(shí)另開一篇具體講解一下作用域的問題缩搅,這里只做簡單闡述。
js中的作用域與其它語言中的作用域有所不同触幼,像著名的C系語言和JAVA中硼瓣,作用域指的是確實(shí)的塊作用域,即被{}包住的代碼塊內(nèi),有獨(dú)立的作用域堂鲤。
#include
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d\n", x); // 1
}
而js中的作用域通常被稱作函數(shù)級(jí)作用域亿傅,及以函數(shù)為單位的作用域。
var a = "1";
(function(){
var a = "2";
console.log(a) ?//2
})();
由此可以看到瘟栖,以函數(shù)為單位的作用域有很強(qiáng)的靈活性葵擎,這里需要說到另一個(gè)概念,即作用域鏈半哟。
在js中 作用域通常會(huì)有一個(gè)鏈條酬滤,子函數(shù)可以訪問父函數(shù)內(nèi)的變量,而父函數(shù)無法訪問子函數(shù)的變量寓涨,關(guān)于這個(gè)敏晤,我在之前的閉包中有詳細(xì)講過,感興趣的童鞋可以去看下缅茉。
而變量提升嘴脾,即是講函數(shù)作用域內(nèi)的變量,提升至函數(shù)頂端蔬墩。
在js的運(yùn)行機(jī)制中译打,會(huì)首先由javascript解釋器將完成對(duì)javascript代碼的預(yù)處理,而后將javascript代碼轉(zhuǎn)換為字節(jié)碼拇颅。
在執(zhí)行期奏司,javascript解釋器借助執(zhí)行期環(huán)境將字節(jié)碼生成機(jī)械碼,并按照順序執(zhí)行樟插,完成程序設(shè)計(jì)的任務(wù)韵洋。
而在編譯期的時(shí)候,js會(huì)將所有變量提升至函數(shù)作用域的頂端黄锤,類似于這樣的運(yùn)行機(jī)制:
(function(){
var a=1;
var b = 2;
var c = 3;
})();
會(huì)被編譯成:
(function(){
var a,b,c;
a = 1;
b = 2;
c = 3;
})()
最重要的就是要注意這里搪缨,變量提升并不會(huì)將賦值一同提升上去,而是先在函數(shù)頂部創(chuàng)建三個(gè)未定義的變量鸵熟,然后在之前定義變量的地方賦值副编,所以這里非常容易報(bào)錯(cuò):
var v='this is variable';
(function(){
alert(v); ?//undefined
var v = "this is variable2";
})()
在這個(gè)例子中,由于alert方法中的v是局部作用域中的變量流强,而此時(shí)變量v只聲明了一個(gè)未定義的變量痹届,還未給其賦值,所以此時(shí)會(huì)報(bào)錯(cuò)undefined打月。
所以js中的變量提升是一個(gè)非常強(qiáng)大的特性队腐,同時(shí)也是個(gè)容易踩坑的特性,大家在使用時(shí)奏篙,一定要注意柴淘,如非必要,我建議將需要使用的變量放在作用域頂部聲明。