JavaScript - Hoisting(提昇)

重點有三:

  1. 變數宣告跟函式宣告都會提升
  2. 只有宣告會提升,賦值不會提升
  3. 別忘了函式裡面還有傳進來的參數

Javascript 執行時會經過創造執行環境的階段。JavaScript 跟其他程式語言不同,它可以在還沒宣告函式前就先呼叫並且執行。在下列的範例中,假如我們把呼叫移到程式碼最上方,函式宣告之前,會發生什麼事?JavaScript 不僅執行函式,而且沒有錯誤。Called b! 正常印出來,代表函式 b 正常執行,但是 undefined 是怎麼回事?

1
2
3
4
5
6
b();
console.log(a);//undefined
var a = "hello world";
function b() {
console.log("called b !"); // "called b !"
}

Javascript 程式碼在執行時,會經過一個創造階段 (creation),並且在記憶體裡為變數與函數建立儲存空間,在記憶體裡設定變數與函數的這個步驟稱為「提昇」(hoisting) 。

不是真的把程式碼移到最上面。所以函式跟它的內容(定義)會先存至記憶體,所以可以正確的呼叫,呼叫後建立這個函式的執行環境,印出 Called b!。雖然變數也在記憶體中建立空間,可是它的內容並沒有在創造階段時被放入。創造變數與賦值給變數可當成兩件事,所以呼叫變數 a 才會印出 undefined

上面的程式碼,在電腦執行時可以想像成這樣的順序,結果會是一樣的:

1
2
3
4
5
6
7
var a;
function b() {
console.log("called b !");
}
b();
console.log(a);
a = "hello world";

下面的例子可以正確執行,因為函數會先在記憶體裡創造空間,並建立它的區域變數,再執行呼叫。

1
2
3
4
5
6
7
b();

function b() {
console.log("called b !"); //called b !
var a = "hello world";
console.log(a); // "hello world"
}

下列的狀況雖然貌似。但是因為 var b 在創造階段被提昇,但還沒有被賦值。接著

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
b();

var b = function() {
console.log("called b !");
var a = "hello world";
console.log(a);
};

//可以想像創造階段是像這樣

var b;

b();

b = function() {
var a = "Hello World!";
console.log(a);
};

變數 b 先被提升 (創造變數 b 並設定進記憶體),接著呼叫執行 b 函式,為變數 b 賦值(指向)函式。呼叫執行 b 函式時報錯,是因為變數 b 這個時候根本沒有被賦值。所以自然報錯 b is not a function。

這種貌似變數與函式被拉到執行環境最前面的現象稱為 Hoisting

另一個例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var foo = 1;
var foobar = function() {
console.log(foo);
var foo = 2;
};
foobar();

//可以想像創造階段是像這樣

var foo = 1;
var foobar = function() {
var foo;
console.log(foo); //undefined
foo = 2;
};
foobar();

區域變數 foo 的宣告會被提昇,先於呼叫 console.log 方法,也就是區域變數的值將會作為參數傳入成為 console.log 得出的值,而不是在函數外部聲明的全域變數。但是,變數宣告不會提升該值,因此輸出將是 undefined,而不是 2。在創造階段,函數跟其函數內容(定義)會先存至記憶體,雖然變數也在記憶體中建立空間,可是它的內容並沒有在創造階段時被放入。所以呼叫變數 foo 才會印出 undefined。

延伸閱讀:
https://blog.techbridge.cc/2018/11/10/javascript-hoisting/
https://github.com/aszx87410/blog/issues/34#issuecomment-500890667

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2020 CYC'S BLOG All Rights Reserved.

UV : | PV :