變量提升和函數(shù)提升的問(wèn)題

關(guān)于變量提升,大家可能都聽(tīng)的耳朵都起繭了。但是最近的一次討論 ,又讓我有了新的認(rèn)識(shí)。

先看看題:請(qǐng)說(shuō)出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。
讓我們來(lái)看看答案:

  1. f a(){alert(10)}
    關(guān)于這個(gè)答案,當(dāng)時(shí)產(chǎn)生的第一個(gè)疑問(wèn)就是,同樣命名,為什么提升之后a反而是function a(){alert(10)},明明是函數(shù)a先提升的,變量a后提升的,為什么打印出來(lái)的不是undefined?曾經(jīng)在網(wǎng)上看到這么一句話(huà),函數(shù)優(yōu)先級(jí)要高于變量?jī)?yōu)先級(jí),相同命名,變量會(huì)被覆蓋。不知道背后的邏輯究竟是怎么樣的。看了https://zhuanlan.zhihu.com/p/28140450這篇文章之后恍然大悟。
    對(duì)于函數(shù)聲明來(lái)講,像如下代碼

     console.log(a)
     function a(){
         console.log('helloworld')
     }
    

    創(chuàng)建,初始化,賦值的過(guò)程如下:

    • 找到所有用 function 聲明的變量,在環(huán)境中「創(chuàng)建」這些變量。
    • 將這些變量「初始化」并「賦值」為 function(){ console.log(2) }。
    • 開(kāi)始執(zhí)行代碼 fn2()
      所以,對(duì)于函數(shù)聲明來(lái)講,在代碼執(zhí)行之前,JS引擎就會(huì)對(duì)其進(jìn)行創(chuàng)建,初始化,賦值
      函數(shù)表達(dá)式就只有創(chuàng)建和初始化過(guò)程。

    對(duì)于變量表達(dá)式/變量聲明來(lái)講,像如下代碼

       console.log(a)
       var a = 2;
    
    • 找到所有用 var 聲明的變量,在環(huán)境中「創(chuàng)建」這些變量。「創(chuàng)建」這些變量(即a)。
    • 將這些變量「初始化」為 undefined。所以上面打印出來(lái)的結(jié)果應(yīng)該是undefined。
    • 執(zhí)行代碼
    • a = 2 將 a 變量「賦值」為 2
    • 也就是說(shuō) var 聲明會(huì)在代碼執(zhí)行之前就將「創(chuàng)建變量,并將其初始化為 undefined」。

    這樣還是解釋不了我的疑惑,為什么明明是函數(shù)a先提升的,變量a后提升的,為什么打印出來(lái)的不是undefined?找了很多資料似乎也就那句話(huà)函數(shù)優(yōu)先級(jí)要高于變量?jī)?yōu)先級(jí),相同命名,變量會(huì)被覆蓋理解不了啊!而且我覺(jué)得這句話(huà)有誤導(dǎo)的嫌疑!
    上文提到過(guò)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
    

    所以上述過(guò)程應(yīng)該這樣子的:

    進(jìn)行變量提升,function a()被提升到作用域的最前面,變量a也進(jìn)行提升了,但是它發(fā)現(xiàn)已經(jīng)有a了,所以沒(méi)有了初始化a為undefined這一步。所以在alert(a)的時(shí)候,依舊是 ? a(){alert('10')}

  2. 10 //執(zhí)行了a(){alert(10)}
    不知道你看懂了嗎????

條件判斷下的函數(shù)提升

上面既然我們已經(jīng)說(shuō)到,對(duì)于函數(shù)聲明(不是函數(shù)表達(dá)式哦)來(lái)講,在代碼執(zhí)行之前,JS引擎就會(huì)對(duì)其進(jìn)行創(chuàng)建,初始化,賦值。但是,遇到條件判斷語(yǔ)句,像下面的:

(function () { 
    if (false) {
        function test() {
            console.log(2);
        }
    }
    test();
})();

在早期的瀏覽器中,會(huì)打印出2,因?yàn)閷?duì)于函數(shù)聲明來(lái)講,在代碼執(zhí)行之前,JS引擎就會(huì)對(duì)其進(jìn)行創(chuàng)建,初始化,賦值。所以就算進(jìn)入條件判斷語(yǔ)句,test()函數(shù)已經(jīng)在當(dāng)前作用域創(chuàng)建并賦值了。
但很明顯,這跟我們的出發(fā)點(diǎn)是背離的,我們寫(xiě)的條件判斷語(yǔ)句完全沒(méi)有意義了!
后來(lái)瀏覽器為了修正這個(gè)錯(cuò)誤,像這種情況下面的函數(shù)提升就只是 var test提升到函數(shù)作用域的頂端,本題中false所以沒(méi)進(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

再來(lái)做做題吧!

解釋一下下面執(zhí)行的結(jié)果

    (function(){
    console.log(a);
    function a(){
        console.log(a);
    }
    var a = 1;
    })() //? a(){console.log(a);}

你看懂了嗎??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容