整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ
JavaScript 核心觀念(61) - ES6 章節:Let 及 Const - Let 有沒有 Hoisting?暫時性死區介紹
前言
接下來這章節將會說明 let 是否有 Hoisting 的問題。
暫時性死區介紹
在很前面的 JavaScript 核心觀念(6)-執行環境與作用域-提升 章節我們有提過提升的問題:
1 | |
這邊也算是簡單的複習一下非常前面的章節,否則看到現在可能都已經忘記了。
基本上 Hoisting 會區分為創造階段與執行階段:
1 | |
而上面的範例是基於 var 來宣告變數的情況,那麼 let 呢?let 也會有相同問題嗎?你可以試著將程式碼修改成以下:
1 | |
相信你輸入以上程式碼的時候應該要出現 Uncaught ReferenceError: Cannot access 'myName' brfore initialization.,如果你是在較新版的 Chrome 瀏覽器輸入你會發現實際上出現的是則是會出現 Uncaught ReferenceError: myName is not defined,而 Firefox 目前我測試 89.0.2(64 位元)版本則是 Uncaught ReferenceError: can't access lexical declaration 'myName' before initialization。
因此這代表著瀏覽器更新之後是會更新錯誤訊息的,這一點要多加注意一下,雖然我覺得 Chrome 的錯誤訊息比較直覺就是了:
1 | |
但是如果是 const 的話,錯誤訊息就沒有太大差異:
1 | |
那麼我們明白了瀏覽器會更新錯誤訊息之後,那我們怎麼知道它有沒有提升呢?其實我們可以翻一下 MDN 文件,有一句話是關鍵:
The variable is in a “temporal dead zone” from the start of the block until the initialization is processed.
在變數完成初始化之前呼叫的話,是會處於暫時性死區 (TDZ),這也就是為什麼會出現 ReferenceError 錯誤,而實際上 let 運作模式有變嗎?其實並沒有,只是會變成 ReferenceError 暫時性死區錯誤:
1 | |
這邊要注意 let 會在 myName = 'Ray'; 之前建立一個暫時性死區的階段,所以你在 myName = 'Ray'; 勢必都會出現 ReferenceError 錯誤的。
那麼我們該怎麼驗證 let 有提升呢?首先一般來說如果你想要 console.log 一個不存在的變數是會得到 Uncaught ReferenceError: xxx is not defined 的,例如:
1 | |
但是如果你使用 console.log(typeof(a)) 則是會出現 undefined,因此我們可以這樣子驗證:
1 | |
因此這邊就可以得到一個結論是「在變數初始化的中間過程,是會生成一個 TDZ 暫時性死區的」。
參考文獻
整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ