在JavaScript中經典的例子:Scope、Scope Chain、Hoist、Temporal Dead Zone

    LeetCode JavaScript 30 Days Challenge

    在 JavaScript 中有很多程式碼運作的方式,讓我們一起來瞭解看看吧!

    Example.1
    從以下例子中你會發現印出的結果,竟然會是在全域宣告的變數 x = 2,
    因為在執行程式碼之前(編譯的階段),把所有宣告的程式碼放入記憶體的位置,這個動作叫做提升(Hoist),
    而 function f() 內部沒有 x 變數,故往 function 外查找的動作叫做範圍鏈(Scope Chain),
    最後得到 x = 2 的數值後印出,過程如下:

    // 宣告全域變數 x 為 2。
    let x = 2
    
    function f(){
      // 印出變數 x 的值,此時區域作用域中查無此變數,故往外查找全域變數 x 的值,即為 2。
      console.log(x); //2
    }
    // 執行函數
    f()
    

    Example.2
    以下程式碼中,第一個 console 往外查找了 x = 2 的變數賦值,再來經過了 x = 3 的重新賦值,
    最後執行第二個 console 的結果,過程如下:

    // 宣告全域變數 x 為 2。
    let x = 2
    
    function f(){
      // 印出變數 x 的值,此時區域作用域中查無此變數,故往外查找全域變數 x 的值,即為 2。
      console.log(x); //2
      
      // 對變數 x 進行重新賦值,由 2 改為 3。
      x = 3
      
      // 印出變數 x 的值,此時 x 的值,即為 3。
      console.log(x); //3
    }
    // 執行函數
    f()
    

    Example.3
    我們一步一步拆解以下程式碼執行的過程:
    1. 宣告全域變數 x,賦值為 2。
    2. 定義函數 f()。
    3. 在函數 f() 中的第一個 console.log(x) 嘗試訪問變數 x,但因為該變數在初始化之前的 TDZ 中,所以拋出錯誤。
    4. 在函數 f() 中宣告區域變數 x,賦值為 3。
    5. 在第二個 console.log(x) 中,印出區域變數 x 的值,即 3。
    6. 呼叫函數 f()。

    // 宣告全域變數 x 為 2。
    let x = 2; 
    
    function f() {
      // 印出變數 x 的值,此時 JavaScript 會在函數範圍內優先使用該區域變數(let x = 3),
      // 但是受到變數提升 (hoisting) 的影響,該變數被先行宣告,但尚未執行初始化賦值(let x = 3),
      // 此時處於暫時性死區 (Temporal Dead Zone, TDZ),因此無法訪問 x 的值,並拋出錯誤。
      console.log(x); // Cannot access 'x' before initialization
    
      // 宣告局部變數 x 為 3。 
      let x = 3;
      
      // 印出變數 x 的值,此時 x 為區域變數的值,即為 3。
      console.log(x); //3 
    }
    
    // 執行函數
    f();