動畫:「變量提高」引起的一場"血"案 !

動畫:「變量提高」引起的一場

寫在前邊javascript

某一外包公司小李,剛剛入門前端以後,老闆就讓他寫一段前端 JS 項目代碼,不料,這時以前學過Java的小李遇到了一個問題,對於常常寫 Java代碼的小李來講,這屬於一個靈異事件。項目中的一段代碼以下:前端

動畫:「變量提高」引起的一場

小李越想越感到納悶,明明我在打印以前,沒有聲明任何的變量呀,爲何還能使用未聲明的變量,從而打印出 a 的值呢,是否是個人編譯器出現了問題?遇到問題的小李,越想越奇怪,就又寫了一段測試代碼。java

動畫:「變量提高」引起的一場

按理說應該輸出undefined呀,爲何會輸出的結果爲 10。小李越想越奇怪,到底哪裏出現問題了。這時老闆過來了,看了看代碼,笑了笑說,你仍是去先學學基礎吧。就這樣,小李在網上找到了小鹿的這篇教程,學完以後,才恍然大悟。面試

思惟導圖ide

動畫:「變量提高」引起的一場

1函數

什麼是變量提高?學習

咱們首先要弄明白什麼是變量提高?顧名思義,從表面上的意思去分析,代碼在真正的執行以前變量就已經進行了提高聲明。是的,確實是這麼個意思,可是咱們後邊的原理部分說的這種所謂的「提高」卻不是真正的提高,而是爲了讓開發者便於理解,纔有了變量提高這以名詞,話說到這,那麼它是如何進行提高的呢?測試

咱們仍是用小李的例子,第一個例子以下:動畫

動畫:「變量提高」引起的一場

首先,程序執行,首先將聲明的變量提高到最前邊,a 變量就會被提高到最前邊,可是並不會進行賦值操做,變量提高完畢以後,代碼自上而下順序執行。輸出 a 的值,a 此時沒有被賦值,因此輸出 undefined,繼續執行,a 被賦值 10,執行完畢。3d

動畫:「變量提高」引起的一場

除此以外,其實不只變量會提高函數也會被提高。

注意:只有 var 聲明的變量或函數纔會進行提高,而 ES6 中的 let 和 const 不會進行提高,後面會講到。

函數提高:

動畫:「變量提高」引起的一場

函數提高優先於變量提高,函數提高會把整個函數挪到做用域頂部,變量提高只會把聲明挪到做用域頂部。

2

爲何須要變量提高?

小李以前有 Java基礎,爲什麼到了 JS 有這種策略,他想不通爲何要這樣,順序執行它不香嗎?

彆着急,咱們舉個例子就說明爲何 JS 中須要變量提高了。以下代碼所示:

動畫:「變量提高」引起的一場

咱們想想,若是 JS 沒有變量提高,這個程序仍是否可以執行呢?咱們在 fn 函數中執行 fn2 函數,若是沒有變量提高,此時的 fn2 尚未聲明,因此找不到,拋出錯誤。

正是因爲 JS 存在變量提高,因此程序執行,fn 和 fn2 函數提高被聲明,而後再去執行下面的代碼,就能夠正常經過編譯執行,是否是很香呢?最後得出結論爲,變量提高存在的根本緣由就是爲了解決函數間互相調用的狀況。

3

變量提高的內部原理

要想知道變量提高的內部原理,咱們就深刻 JS引擎的工做原理。javascript代碼的執行事實上是分兩個階段進行的。

一旦 JS 建立了詞法環境——程序執行的環境,就會執行第一階段。在第一階段,沒有執行代碼,可是javascript引擎會訪問並註冊在當前詞法環境中所聲明的變量和函數 —— 咱們上邊所說的變量和函數聲明的提高。javascript在第一階段完成以後開始執行第二階段,代碼自上而下順序執行。

具體第一階段是如何執行的呢?

一、若是咱們聲明的是一個函數環境,那麼咱們在詞法環境中建立形參和函數參數的默認值,若是是非函數(全局做用域下),那麼就跳過這個步驟。

2、若是是建立全局或函數環境,就掃描當前代碼進行函數聲明,不會掃描其餘函數的函數體。可是不會掃描函數表達式或箭頭函數。若是是塊級做用域的話(ES6 的知識),跳過此步驟。

3、掃描當前代碼進行變量聲明。在函數或全局環境中,找到全部當前函數以及其餘函數以外經過var聲明的變量,並找到全部在其餘函數或代碼塊以外經過let或const定義的變量。

在塊級環境中,僅查找當前塊中經過 let或 const定義的變量。對於所查找到的變量,若是沒有賦值,則標記爲 undefined;不然,對變量進行賦值。

整個處理過程以下圖:

動畫:「變量提高」引起的一場

咱們不少人認爲,變量的聲明提高至函數頂部,函數的聲明提高至全局代碼頂部。可是,咱們知道原理以後,並無那麼簡單。

聲明:變量和函數的聲明並無實際發生移動。只是在代碼執行以前,先在詞法環境中進行註冊。雖然描述爲提高了,而且進行了定義,這樣更容易理解 JavaScript 的做用域的工做原理,可是,咱們能夠經過詞法環境對整個處理過程進行更深刻地理解,瞭解真正的原理。

4

如何解決變量提高問題?

若是咱們不想讓變量或函數進行變量提高,咱們有沒有好的解決辦法?

有的,在 ES6 新標準中,提供了 let和 const來聲明變量,若是咱們用 let和 const在聲明以前使用了 a,程序就會拋出錯誤。咱們把這個錯誤叫作暫時性死區,就是說咱們不能在變量聲明以前使用變量。

動畫:「變量提高」引起的一場****

那麼問題來了,var和 let/const聲明的變量除了變量提高外,有什麼本質上的區別呢?

第一,var聲明的全局變量會綁定在window對象上,而 let和 const 聲明的變量不會掛在到全局變量 window上。

動畫:「變量提高」引起的一場

動畫:「變量提高」引起的一場

第二,let和 const 區別就是,後者不能進行二次賦值。

5

大廠面試題解析

既然咱們學了這麼多有關變量提高的知識,光說不練假把式,直接上大廠面試題,檢測一下你是否真正的掌握了變量提高。

動畫:「變量提高」引起的一場

咱們更具上邊小鹿總結的規律,咱們把這個大廠的題給梳理一遍。

程序執行,建立一個執行環境(詞法環境),而後下一步將能夠進行提高的變量進行提高,咱們上邊說過有哪幾類是不能提高的?箭頭函數、表達式。並且函數的提高會優先於變量的提高。說到這裏,你必定知道這個題答案了,很明顯的,答案爲 8 。若是你沒有作對,再將從頭看一下文章哦!

6

小結

小李看到這裏,立刻就明白了項目出現的奇怪現象,後來小李被老闆升職加薪了.....

寫到這裏,對於每一個基礎的知識點要打牢,尤爲是對於初學者,前期學習來很浮躁,好比:變量提高,知道有這麼一回事,可是他並不知其因此然。有的小夥伴會問,學這麼詳細圖個什麼?

這個問題問的好,之因此小鹿將技術點分享的很詳細,拆解的很散,可是有句話說的好,「授人以魚,不如授人以漁」。我但願更能把這種學習的態度和方法分享給你們,一篇文章不止學到了一個知識點,而是可以提取出,屬於本身的東西。這對你後期閱讀源碼等有很大的提高和幫助!

相關文章
相關標籤/搜索