Javascript塊級域內的函數聲明提高

主題

昨天個人一個技術交流羣裏發了一段代碼,涉及的是變量和函數的聲明提高,執行結果很是讓人迷惑,你們討論許久,仍是有地方解釋不清楚,到最後,仍是發佈到stack overflow,經過大佬解惑才弄明白,這裏我再整理一下。javascript

個人思路

逐個解析一下討論到的案例:html

沒有特別說明的,運行環境就是是chrome77。
var a
  if(true) {
    a = 5
    function a() {}
    a = 0
    console.log(a)
  }

  console.log(a)

先整理一下個人思路:java

  • 首先,全局有一個變量a聲明;
  • 而後,有一個if語句塊,是一個塊級做用域;
  • 塊級做用域裏面有變量a的賦值,還聲明瞭一個函數a

按照聲明提高原則,函數a聲明會被提高,這裏沒有使用letconst,因此我按ES5以前的聲明提高規則去分析的。es6

沒有塊級做用域,提高到全局,並且函數聲明優先於變量聲明,因此會覆蓋變量a的聲明。web

那麼答案是:chrome

0
0

很遺憾,這個答案是錯的,至少現代瀏覽器是錯的(我後來在IE的模擬環境運行,確實是這個結果)。瀏覽器

如今,公佈一下正確答案函數

0
5

這個答案很是讓人疑惑不解:code

  • 第一個輸出0,好理解
  • 第二個輸出5,究竟是怎麼回事?htm

    • 若是理解成:let a = function(){},那麼a=5是暫時性死區;
    • 若是理解成:var a = function(){},那麼會和上面同樣,輸出0 0

大佬的解析

先看看代碼運行解析[引用1],咱們能夠把代碼運行當作這樣:

var a¹;
 if (true) {
   function a²() {} // hoisted
   a² = 5;
   a¹ = a²; // at the location of the declaration, the variable leaves the block      
   a² = 0;
  console.log(a²)
}
console.log(a¹);

解釋一下:

  • 全局的變量a聲明,這裏沒有問題。
  • 重點1,塊級域的函數a聲明提高,提高到塊級域頂部
  • 重點2a=5,這裏賦值的對象是本地的函數a,覆蓋了。
  • 重點中的重點,執行到函數a聲明處,本地的變量a覆蓋了全局的變量a。按照[引用2]解釋,這裏也是提高,也就是說函數a聲明提高了兩次。到這裏疑惑終於解開了!

總結

這裏要說明兩點:

  • 塊級做用域{}內的函數聲明,在ES5中是非法的,在ES6中並無嚴格規定(考慮到向下兼容性,參考阮老師的ES6入門),也就是這塊依賴於實現[引用3]。
  • 在項目裏面,不要在塊級做用域{}內聲明函數,要在全局做用域或者函數做用域的頂層聲明函數。

引用參考

  1. [confused about function declaration in { }

](https://stackoverflow.com/que...

  1. [What are the precise semantics of block-level functions in ES6?

](https://stackoverflow.com/que...

  1. web legacy compatibility semantics
相關文章
相關標籤/搜索