[JS] Hoisting 提升

hoisting 提升

hoisting 提升的作用使變數和函數的宣告看起來移動到程式碼的頂端,但實際上並非如此,而是程式在編譯期間在宣告變數和函數的部分會先建立記憶體空間,在執行的時候才會將值賦予到該記憶體空間。

看後面的程式來了解更多 hoisting 的特性。

變數的 hoisting

  • 對未宣告的變數存取時拋出 not defined 的錯誤

    1
    console.log(a); // Uncaught ReferenceError: a is not defined

  • hoisting 的作用使宣告的變數值為 undefined

    1
    2
    console.log(a); // undefined
    var a = 10;

可以將以上程式想像成以下(之所以為想像是因為原理並不是真的 JavaScript 引擎會將程式碼變換成如下)

1
2
3
var a;
console.log(a) // undefined
a = 10;

第 1, 2 行由於宣告但還未賦予值,所以為 undefined,由此可以看出將 var a = 10 拆解成 var aa = 10 兩部分,只有 var a 宣告的部分會有 hoisting 的效果,賦值則不會。

函式的 hoisting

上面的例子為變數的 hoisting,但 function 也有 hoisting,關於 function 的部分又可分為 var a = function() {...}function a() {...} 兩種來看。

  • 函式運算式 var a = function() {...}
    1
    2
    3
    4
    5
    x(); // Uncaught TypeError: a is not a function

    var x = function() {
    console.log('test');
    };
    相當於以下
    1
    2
    3
    4
    5
    6
    var x;
    x(); // Uncaught TypeError: a is not a function

    x = function() {
    console.log('test');
    };
    可以看到只有 var x 宣告變數的部分提升,後面指定 function 的部分則不會提升。

所以函式運算式不會提升。

  • 函式宣告 function a() {...}
    1
    2
    3
    4
    5
    x(); // test

    function x() {
    console.log('test');
    }
    從結果可以看出來宣告函式會連同內容一起提升,所以在程式碼中可以在宣告之前使用函式。

所以函式宣告會提升。

函式及變數同名的 hoisting

雖然實務上不會將變數及函式命名一樣的名稱…,但這部分也有規律所在就來了解一下。

  • 函式與變數同名,函式會優先於變數

    1
    2
    3
    4
    5
    6
    7
    console.log(x); // ƒ x() {...}

    var x;

    function x() {
    console.log('test');
    }

    從結果不是 undefined 可以看出即使變數和函數都提升,函式會優先變數。


  • 多個變數同名
    這裡要說的多個變數同名情況很多人以為最後宣告沒有賦予值所以 x 會是 undefined,但結果卻是 5

    1
    2
    3
    4
    var x = 5;
    var x;

    console.log(x); // 5

    以上代碼相當於以下,仍然是基礎的 hoisting 特性

    1
    2
    3
    4
    5
    var x;
    var x;
    x = 5;

    console.log(x); // 5

  • 多個函式同名,最後宣告的會覆寫前面的宣告

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    x(); // 3

    function x() {
    console.log(1);
    }

    function x() {
    console.log(2);
    }

    function x() {
    console.log(3);
    }


參考資料

  1. 提升(Hoisting)
  2. 鐵人賽:JavaScript Function 與 Hoisting
  3. 重新認識 JavaScript: Day 10 函式 Functions 的基本概念
  4. 你懂 JavaScript 嗎?#13 拉升(Hoisting)
  5. 我知道你懂 hoisting,可是你了解到多深?