JavaScript Hoisting
在 JavaScript 中宣告的變數和函數,會被 JavaScript 直譯器 (interpreter) 先處理,換句話說,你在 global 或 function 任何位置宣告一個變數,就像在該 scope 最開頭的位置宣告一樣,這種特性就叫做 Hoisting (提升)。
因為 Hoisting 這特性,變數和函數宣告會被隱性的搬到 scope 的最上方,也造成為什麼一個變數可以在宣告之前就能被引用。
例如:
bla = 2;
var bla;
上面的程式執行起來會跟下面一樣:
var bla; // 函數宣告被隱性拉到最上方
bla = 2;
變數還沒宣告就被引用也不會出錯:
function foo() {
alert(a);
var a;
}
// 顯示 undefined,而不是錯誤 ReferenceError: a is not defined
foo();
let 與 const 的 Hoisting
在 ES6 之後,我們有了 let 和 const。這兩個關鍵字 declared 的變數,其實也會被 Hoisting,但是它們不會被初始化 (not initialized)。
這意味著變數雖然已經在記憶體中存在,但在程式執行到「宣告的那一行」之前,你完全不能存取它。這段「變數已存在但無法存取」的區域,被稱為 Temporal Dead Zone (TDZ, 暫時性死區)。
console.log(bar); // ReferenceError: Cannot access 'bar' before initialization
let bar = 10;
這與 var 的行為不同:
var:Hoisting 且初始化為undefined-> 可以存取,得到undefined。let/const:Hoisting 但沒有初始化 -> 存取會拋出錯誤 (Error)。
這其實是更好的設計,因為它避免了變數在未預期的情況下被使用,讓程式碼邏輯更安全。
總結
也因為 JavaScript 隱性的 Hoisting,一般好的習慣是將變數宣告都放在最上方 (Declare variables at the top),讓程式邏輯更清楚,也可以避免預期外的結果或錯誤發生。