首先把問題放出來,昨天看了一個掘友發的一個問題,而後跟我同事一塊兒研究了一下,沒找出來是爲何,而後我回來一直在想爲何,而後各類找資料研究,從各個方面找爲何,好比js上下文,做用域,js垃圾回收,堆棧調用狀況等等。javascript
首先若是不看上面的圖,以你如今知道的js知識,你以爲打印出來應該是什麼。第二張圖其實打印出來的結果在乎料之中,緣由就是函數聲明提高,沒問題,可是第一張圖爲何呢?這裏能夠發散一下思惟,好比說是否是在塊做用域中,變量和函數之間存在某種互相覆蓋的問題啊,或者說先在塊中聲明的會被掛載到全局的window對象下面,後面聲明的就掛載不上去了,而且不會覆蓋,而後能夠把代碼稍微改改,驗證一下你的思想,頗有意思。而後下面咱們斷點調試看下:html
此時咱們再看a在塊做用域中就已是方法了,注意此時我function a(){}
這段代碼還沒走完呢,這就說明函數聲明在js解析(注意是解析不是執行)的時候被提高到了代碼塊頂部,進花括號的那一刻起,函數就已經被聲明瞭,咱們再往下面一步走java
此時a無論在塊做用域仍是全局做用域中都變成了a函數,那這裏是否是能夠理解爲運行上面一行代碼,而後就給全局變量下的a賦值爲函數呢,咱們再看下一步git
當a=50;
走完以後,也就出了塊做用域,此時咱們看到沒有了塊做用域,由於已經出了塊做用域了,而後全局對象window裏面a仍是函數,並非50,可是若是你在塊做用域a後面加一行的斷點看的話,此時塊做用域裏面的a的值爲50,問題就在這裏,爲何此時塊做用域裏面的a的值跟全局window對象下面的值結果不同呢?es6
而後咱們再往下走一步:github
而後進第二個塊做用域,發現跟前面進第一個塊做用域同樣,還沒執行第一行,塊做用域裏面的b已是函數了,緣由也跟第一個同樣js解析的時候函數聲明提高,而後咱們再往下走一步:web
這一步走完咱們發現塊做用域裏面的b已經變成50了,可是全局window對象下面的b仍是undefined,這我也不知道爲何,那我也就只能說此時b是定義在塊做用域中的內部變量了,再往下走一步bash
可是當我走出塊做用域的時候,b居然在全局對象下變成了50,那就證實我上面說的不對,b不是塊做用域中的內部變量,由於此時執行完方法立馬就出塊做用域了,咱們看的不是很清楚,咱們在方法下面加一行代碼,方便調試看結果:函數
確實是當我b函數那一步走完,塊做用域和全局對象window下面的b都變成了50,那我這裏我就認爲是函數b在js解析的時候就被提高到了塊做用域的最上面,執行到b函數那一步其實在以前就已經執行過了,至關於js執行的時候代碼變成下面這樣:post
{
function b() {};
b = 50;
}複製代碼
咱們再看這個代碼不正是上面a那一個塊做用域的代碼嗎,因此在塊做用域中js執行的時候上下兩個塊做用域中是同樣的,因此在塊做用域中打印a,b獲得的結果都是50,而後下一步:
出了塊做用域,就只有全局對象window了,而後window對象下面的b仍是50,因此最後打印出來也是50。走到這一步就全部的步驟都走完了,那麼咱們再回頭看上面的a爲何塊做用域中的值跟window對象下面的a的值不同,經過走完下面一個代碼塊咱們發現上面代碼塊跟下面代碼塊只有函數放的位置不同,結果就不同,那咱們就看一下這裏函數聲明提高究竟是怎麼提高的。
而後我就找到阮一峯博客裏面寫的關於es6塊級做用域的文章:
es6.ruanyifeng.com/#docs/let#%…
另外一篇關於js變量的生命週期的文章:
dmitripavlutin.com/variables-l…
在第一篇文章中,看見裏面有真麼一段話: