1. 程式人生 > >javascript宣告提升

javascript宣告提升

前段時間閱讀一本書《ESCMScript 6入門》,其中一章關於”let和const命令”有一段程式碼

var tmp = new Date()
function f(){
    console.log(tmp)
    if(false){
        var tmp = 'hello world'
    }   
}

關於變數宣告提升,思量許久,寫了以下理解。

這段程式碼看似簡單,其內部隱藏著重要的知識點“變數提升”這一現象。一般理解,呼叫f函式tmp要麼打印出日期,要麼打印出undefined,結果為後者。為何?

書本上僅僅這麼說明:原因在於變數提升,導致內層tmp變數覆蓋了外層tmp變數

僅僅理解這句話並不能清楚的知道為何?

再來看下面的程式碼:

function f(){
    var item1 = 1;
    var item2 = 'str';
    var item = [1]
}

經過編譯器預處理類似變成:

function f(){
    var item1,item2,item3;
    item1 = 1;
    item2 = 'str'
    item3 = [1]
}

經過編譯器處理只會將所有的變數進行統一的宣告處理,所以,案例中經典的程式碼可以改為:

var tmp = new Date();
function
f(){
var tmp; console.log(tmp); if(false){ var tmp = 'hello world'; } }

總結:變數提升分為宣告提升和定義提升,賦值或者初始話並不會被提升,而程式碼中出現if條件語句,雖然程式碼不會進入那個片段,但是編譯器會預處理裡面的程式碼,將宣告tmp提升到f函式的最頂層,之所以覆蓋全域性,是因為內部已經聲明瞭tmp變數,將外部全域性變數對f函式的tmp的搜尋值遮蔽,因函式存在宣告,tmp變數就不再往上層去搜索值(原型鏈搜尋),這與物件的原型方法搜尋類似。

2018-09-06

上文是我在兩個月前寫的let變數提升的理解,但是自從面試之後,發現不僅僅那麼簡單,面試官這樣問我:var存在變數宣告提升,那let會麼?按照MDN文件的解釋,因為let存在暫時性死區,所以無法進行變數宣告提升。但真的是這樣簡單的理解了麼,下面我來把真正的原因講一下。

在MDN文件描述了let的知識,總結有一下三條:

  1. let宣告變數的作用是塊級的;
  2. let不能重複宣告一已經存在的變數;
  3. let存在暫時性死區,變數宣告不會被提升。

雖然你理解了上面三個總結,但是你的理解和對let的全面理解並不深刻。

let是否存在變數提升問題?

其實所有宣告變數的關鍵字,都存在變數宣告提升這個功能,只不過有些可以表現出這個特性,如var,有些不能,如let,為什麼let不能呢,暫時性死區又怎麼作用於它呢?

MDN文件在let上前後進行了兩次修改,所以其作者也是舉起不定,我們翻看es文件,會發現一段話: The environment of with statements cannot contain any lexical declaration so it doesn't need to be checked for var/let hoisting conflicts。 這句話證明了let存在變數提升。提升不是一個技術名稱,js變數被宣告的過程:建立、初始化、賦值。

  • var在建立和初始化的過程中都被提升;
  • let在建立會被提升,而初始化沒用被提升,因為暫時性死區(變數在未使用之前,不能使用該變數);
  • 函式建立、初始化和賦值都被提升; const只有建立和初始化過程,沒有賦值過程。

總結:

  • let 具有變數提升過程,但不表現這個過程,因為存在暫時性死區;
  • let 建立會被提升,但初始化不能被提升;
  • 所有變數宣告的關鍵字操作都存在變數提升這個過程,只是因為不同情況和性質導致是否需要表現出來。

(文章結合自己思考和參考一些資料,如有侵權請聯絡本人,會盡快處理)。