[一道題搞蒙你] - js預處理和各種提升

MirrorXu發表於2018-10-11

請聽題:


var c = 1;

function c(c) {
    console.log(c);
    var c = 3;
}

c(2);

複製程式碼

執行結果:

// 直接給你報錯
TypeError: c is not a function
複製程式碼

解析:

  • 第一個坑(預處理):

    js語言本身具有預處理機制,js引擎在預處理期對所有宣告的變數和函式進行處理,就是先把變數進行宣告並讀到記憶體裡。也就是收集用var宣告的變數資訊和函式宣告資訊。變數和函式的優先順序:先變數後函式。當變數名和函式名一致時後者會覆蓋前者,來個小?:

        function b() { };
        var b ;
        console.log(typeof b)  // function
    複製程式碼

    看啥看,就是function服不服? 接著再來個小?:

        function b() { };
        var b = 1 ;
        console.log(typeof b)  // number
    複製程式碼
  • 第二個坑(作用域域預處理):

    js中存在兩種作用域,全域性作用域函式作用域, 預處理過程中的變數和函式提升都是在作用域上下文內進行。廢話不多說,再來吃個?:

        var a = 2  
        function fn() {  
            console.log(a)  
            var a = 3  
        }  
        fn() // undefined
    複製程式碼

    為什麼是undefined呢? 全域性作用域和fn函式作用域內變數、函式分別進行提升。當fn呼叫時,外層全域性作用域的變數a值未2但是這並沒什麼卵用,因為在fn的函式作用域內也宣告瞭一個變數a,函式作用域內的變數a也會進行提升,當console.log(a)語句執行的時候,fn作用域內的a變數宣告但未賦值,所以輸出undefined

  • 回到本文?: 當本文中的例子預解析各種提升完成以後,實際執行時的環境是這樣的:

        var c ;
        c = function (c) {
            console.log(c);
            var c = 3;
        };
        c = 1 ;
        
        c(2);   // TypeError: c is not a function
    複製程式碼

補充:

es6+中,還存在塊作用域 ,結合letconst等關鍵字進行變數的生命能夠避免很多問題,在本文中不再進一步討論,有興趣的同學可以去查一下。話又說回來,如果你沒在ES6 前踩過這些坑,其實很難理解ES6 為什麼會那麼搞。

相關文章