關(guān)于變量提升,大家可能都聽的耳朵都起繭了。但是最近的一次討論 鹃两,又讓我有了新的認(rèn)識(shí)遗座。
先看看題:請(qǐng)說出1,2對(duì)應(yīng)序號(hào)的結(jié)果
alert(a) 1
a(); 2
function a(){
alert(10)
}
var a=3;
很明顯由于變量提升俊扳,在執(zhí)行alert(a)之前途蒋,function a和變量a已經(jīng)被初始化了,所以alert(a)其實(shí)是有值的馋记,而不是is not defined号坡。
讓我們來看看答案:
-
f a(){alert(10)}
關(guān)于這個(gè)答案,當(dāng)時(shí)產(chǎn)生的第一個(gè)疑問就是梯醒,同樣命名宽堆,為什么提升之后a反而是function a(){alert(10)},明明是函數(shù)a先提升的茸习,變量a后提升的畜隶,為什么打印出來的不是undefined?曾經(jīng)在網(wǎng)上看到這么一句話,函數(shù)優(yōu)先級(jí)要高于變量優(yōu)先級(jí)号胚,相同命名籽慢,變量會(huì)被覆蓋。不知道背后的邏輯究竟是怎么樣的猫胁∠湟冢看了https://zhuanlan.zhihu.com/p/28140450這篇文章之后恍然大悟。
對(duì)于函數(shù)聲明來講弃秆,像如下代碼console.log(a) function a(){ console.log('helloworld') }
創(chuàng)建届惋,初始化,賦值的過程如下:
- 找到所有用 function 聲明的變量菠赚,在環(huán)境中「創(chuàng)建」這些變量脑豹。
- 將這些變量「初始化」并「賦值」為 function(){ console.log(2) }。
- 開始執(zhí)行代碼 fn2()
所以衡查,對(duì)于函數(shù)聲明來講瘩欺,在代碼執(zhí)行之前,JS引擎就會(huì)對(duì)其進(jìn)行創(chuàng)建峡捡,初始化,賦值
函數(shù)表達(dá)式就只有創(chuàng)建和初始化過程筑悴。
對(duì)于變量表達(dá)式/變量聲明來講们拙,像如下代碼
console.log(a) var a = 2;
- 找到所有用 var 聲明的變量,在環(huán)境中「創(chuàng)建」這些變量阁吝⊙馄牛「創(chuàng)建」這些變量(即a)。
- 將這些變量「初始化」為 undefined。所以上面打印出來的結(jié)果應(yīng)該是undefined装盯。
- 執(zhí)行代碼
- a = 2 將 a 變量「賦值」為 2
- 也就是說 var 聲明會(huì)在代碼執(zhí)行之前就將「創(chuàng)建變量坷虑,并將其初始化為 undefined」。
這樣還是解釋不了我的疑惑埂奈,為什么明明是函數(shù)a先提升的迄损,變量a后提升的,為什么打印出來的不是undefined?找了很多資料似乎也就那句話
函數(shù)優(yōu)先級(jí)要高于變量優(yōu)先級(jí)账磺,相同命名芹敌,變量會(huì)被覆蓋理解不了啊垮抗!而且我覺得這句話有誤導(dǎo)的嫌疑氏捞!
上文提到過var 聲明會(huì)在代碼執(zhí)行之前就將「創(chuàng)建變量,并將其初始化為 undefined」冒版。但是液茎,如果發(fā)現(xiàn)已經(jīng)這個(gè)變量在前面賦值了,就不會(huì)有初始化這一步為undefined這一步辞嗡,看代碼:function a(){console.log('hello')}; var a; console.log(a)//? a(){console.log('hello')} function a(){console.log('hello')}; var a = undefined; console.log(a)//undefined
所以上述過程應(yīng)該這樣子的:
進(jìn)行變量提升捆等,function a()被提升到作用域的最前面,變量a也進(jìn)行提升了欲间,但是它發(fā)現(xiàn)已經(jīng)有a了楚里,所以沒有了初始化a為undefined這一步。所以在alert(a)的時(shí)候猎贴,依舊是
? a(){alert('10')}
10 //執(zhí)行了a(){alert(10)}
不知道你看懂了嗎班缎??她渴?达址?
條件判斷下的函數(shù)提升
上面既然我們已經(jīng)說到,對(duì)于函數(shù)聲明(不是函數(shù)表達(dá)式哦)來講趁耗,在代碼執(zhí)行之前沉唠,JS引擎就會(huì)對(duì)其進(jìn)行創(chuàng)建,初始化苛败,賦值满葛。但是,遇到條件判斷語句罢屈,像下面的:
(function () {
if (false) {
function test() {
console.log(2);
}
}
test();
})();
在早期的瀏覽器中嘀韧,會(huì)打印出2,因?yàn)閷?duì)于函數(shù)聲明來講缠捌,在代碼執(zhí)行之前锄贷,JS引擎就會(huì)對(duì)其進(jìn)行創(chuàng)建,初始化,賦值谊却。所以就算進(jìn)入條件判斷語句柔昼,test()函數(shù)已經(jīng)在當(dāng)前作用域創(chuàng)建并賦值了。
但很明顯炎辨,這跟我們的出發(fā)點(diǎn)是背離的捕透,我們寫的條件判斷語句完全沒有意義了!
后來瀏覽器為了修正這個(gè)錯(cuò)誤蹦魔,像這種情況下面的函數(shù)提升就只是 var test
提升到函數(shù)作用域的頂端激率,本題中false所以沒進(jìn)入函數(shù)體,所以test()就會(huì)報(bào)錯(cuò)test is not a function勿决。而不是像第一題那樣乒躺,整個(gè)函數(shù)體都提到前面。
除了if低缩,好像while嘉冒,switch,for也一樣咆繁。
ecma文檔:http://www.ecma-international.org/ecma-262/6.0/index.html
再來做做題吧讳推!
解釋一下下面執(zhí)行的結(jié)果
(function(){
console.log(a);
function a(){
console.log(a);
}
var a = 1;
})() //? a(){console.log(a);}
你看懂了嗎?玩般?