JS 因爲語言設計的缺陷(工期不夠?),裏面有一些堪稱神奇的特性,初學者碰到後可能會滿臉黑人問號,今天要介紹的就是其中的一個特性:聲明提高(Hoisting)。javascript
若是你是一個 JS 新手,有時候會碰到 undefined
或者 ReferenceErrors
錯誤,而聲明提高有可能就是罪魁禍首。java
聲明提高
經常被解釋爲:把變量和函數放到文件的頂部,雖然表面上看起來是這樣,但事實卻不是如此。git
當 JS 引擎開始解析咱們的腳本,第一件事就是爲咱們代碼中的變量 設置內存。這個階段代碼還 沒有運行,只是在爲後面的代碼執行作準備,這個階段就是 編譯階段。github
這一階段的一部分工做就是 找到全部的聲明,並用合適的做用域將它們關聯起來(有關做用域的部分咱們下篇再講)。函數
好比 var a = 2;
JS 引擎會將其看做兩個聲明:var a;
和 a = 2;
。第一個定義聲明在編譯階段進行,第二個賦值聲明會被 留在原地
等待執行階段。oop
而在編譯階段中,函數聲明和變量的聲明存儲方式是不一樣的。spa
函數聲明的存儲,在內存中存儲的是整個函數的引用。(注意 函數聲明 和 函數表達式 的區別)翻譯
下圖的代碼,咱們先看其中的函數 sum
的聲明:設計
變量的存儲不太同樣。ES6 中引入了兩個新的關鍵字:let
和 const
,凡是用這兩個關鍵字定義的變量,存儲的值爲 uninitialized
code
用 var
聲明的變量,存儲的時候默認值爲 undefined
如今編譯階段已經完成,JS 引擎該執行代碼了。咱們在文件頂部添加三個 console.log
語句。
上面講過,在編譯階段因爲 函數聲明 存儲的是整個函數的引用,因此即便在函數聲明以前也能夠調用函數。
若是咱們提早使用 city
這個變量,就會打印出 var
關鍵字定義的默認值 undefined
。而大多數狀況下,這個行爲是使人困惑的,由於你並不指望它的值是 undefined
。
正是爲了解決 var
的問題,因此纔會有了 const
和 let
,當咱們提早訪問它們定義的變量的默認值 uninitialized
時,就會拋出 ReferenceError
。這個行爲有一個霸氣的名字:臨時死區(Temporal Dead Zone),即你不能在這個變量初始化前訪問它。
當 JS 引擎繼續往下解釋代碼時,解釋到某一行有賦值語句時,即會將內存中的值覆蓋爲代碼中定義的值。
(上圖中編號應該是 7 哈~)
來回顧一下:
var
聲明的變量存儲的默認值是 undefined
,let
和 const
聲明的變量的默認值爲 uninitialized
不知道有沒有講明白呢?本文翻譯於做者 Lydia Hallie
的系列文章,部份內容做了詳細解釋,下面還有三篇,歡迎訂閱公衆號關注更新哈:
本文首發於公衆號:碼力全開(codingonfire)
關注並回復 副業
, 獲取技術人的副業祕籍