Javascript 提升(Hoisting)

介紹

提升(Hoisting)是在 ECMAScript® 2015 Language Specification 裡面找不到的專有名詞。它是一種釐清 JaveScript 在執行階段內文如何運行的思路(尤其是在創建和執行階段)。然而,提升一詞可能會引起誤解:例如,提升看起來是單純地將變數和函式宣告,移動到程式的區塊頂端,然而並非如此。變數和函數的宣告會在編譯階段就被放入記憶體,但實際位置和程式碼中完全一樣。 by. MDN

創造環境與執行

在創造環境的時候會先將 a 變數寫入記憶體,執行環境才將 1 賦予給 a。

函式陳述式創造階段

而函式陳述式在創造環境就被寫入,在執行任何程式碼前,JavaScript 會把函式宣告放進記憶體裡面,這樣做的優點是:可以在程式碼宣告該函式之前使用它。

範例

範例 1

函式與變數範例

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

// 以下輸出 你好
function hello() {
console.log("你好");
}
hello();

將以上程式碼拆解,就可以看到 a 是在執行階段才被賦予值,而函式陳述式在創造階段就被創造所以可以輸出”你好”

// 創造階段
var a;
// 執行階段
console.log(a);
a = 1;

// 創造階段
function hello() {
console.log("你好");
}
// 執行階段
hello();

範例 2

函式範例

var hello = function () {
console.log("函式表達式");
};
function hello() {
console.log("函式陳述式");
}
hello(); // 函式表達式

他會輸出 ‘函式表達式’ 因為創造階段函式優先,將以上分解

// 創造階段
var hello;
function hello() {
console.log("函式陳述式");
}
// 執行
hello = function () {
console.log("函式表達式");
};

hello(); // 函式表達式

範例 3

再看看這個範例

// 以下輸出 undefined
hello();
function hello() {
console.log(text);
}
var text = "Hello World";

將範例依照上面所說邏輯拆解,就可以看到在函式呼叫時,還未將 text 賦予 Hello World,所以會輸出 undefined

// 創造階段
function hello() {
console.log(text);
}
var text;

// 執行
hello(); // undefined
text = "Hello World";

範例 4

看到可能會想說怎麼不是先輸出’我是第一個函式’再輸出’我是第二個函式’

function hello() {
console.log("我是第一個函式");
}
hello(); // 我是第二個函式
function hello() {
console.log("我是第二個函式");
}
hello(); // 我是第二個函式

來將上述範例分解,可以看到輸出’我是第一個函式’的函式被覆蓋掉了,所以都會輸出相同內容

// 創造階段
function hello() {
console.log("我是第一個函式");
}
function hello() {
console.log("我是第二個函式");
}

// 執行
hello();
hello();