Skip to main content

JavaScript Hoisting 筆記

JavaScript 在建立執行環境的時候,會分為兩個階段

  1. 創造階段
  2. 執行階段

在創造階段的時候,會先靜態解析程式碼,找出 變數宣告與函數宣告,先替他們預留記憶空間,其中

  • 函數 : 完整的函數程式碼都先放入記憶體
  • 變數 : 先宣告並準備記憶體空間,但值還是 undefined,執行階段才會賦值

這種作法就會形成一種把所有函數都放在程式碼最前面執行的錯覺

console.log(myName); // undefined
// 而非 Uncaught ReferenceError: myName is not defined

greeting(); // Hi

var myName = "Alex";
function greeting() {
console.log("Hi");
}

var x = 1 會被拆解成

var x : 在創造階段先宣告

x = 1 : 在執行階段賦值

函數陳述式、函數表達式

var fn = function () {
console.log("這是函數表達式");
// 像是把一個匿名函數 塞進 一個變數裡
};

function fn() {
console.log("這是函數陳述式");
// 最一開始接觸的函數宣告方式
}

fn(); // 這是函數表達式

明明 function fn() 在比較後面宣告,為什麼最後還是輸出 「這是函數表達式」呢?

我們來拆解以下步驟 :

  1. 創造階段開始
  2. 指派 function fn (){...} 完整內容
  3. 宣告 var fn ( 未賦值 )
  4. 執行階段開始
  5. function () 內容,賦值到 fn 變數,因為執行階段才開始賦值
  6. 執行 fn() ,輸出 「這是函數表達式」

letconst TDZ

前段提到 var 有提升的效果,在變數宣告前就先取用變數的話會是 undefined,而非 Uncaught ReferenceError

console.log(myName);
var myName = "Alex";

但是 letconst 可就不是這樣了

console.log(myName); // Cannot access 'myName' before initialization
let myName = "Alex";

Temporal dead zone 指的是,若在 let / const 宣告以前的區域,就試圖取得變數,會跳出錯誤,提醒你不要用這麼不符合邏輯的方式進行開發

Reference

我知道你懂 hoisting,可是你了解到多深?

帶你無痛提升 JavaScript 面試力 - Chapter 1 卡斯伯著