---
# System prepended metadata

title: Javascript 提升（Hoisting）
tags: [Javascript]

---

---
tags: Javascript
---
# Javascript 提升（Hoisting）

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

## 創造環境與執行

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

![](https://i.imgur.com/f4VbIR1.jpg)

## 函式陳述式創造階段

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

![](https://i.imgur.com/xHSMtNn.jpg)

## 範例

### 範例1
函式與變數範例
```javascript=
// undefined
console.log(a);
var a = 1;

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

將以上程式碼拆解，就可以看到a是在執行階段才被賦予值，而函式陳述式在創造階段就被創造所以可以輸出"你好"
```javascript=
// 創造階段
var a;
// 執行階段
console.log(a);
a = 1;

// 創造階段
function hello() {
    console.log("你好");
}
// 執行階段
hello();
```
### 範例2
函式範例
```javascript=
var hello = function () {
    console.log("函式表達式");
};
function hello() {
    console.log("函式陳述式");
}
hello(); // 函式表達式
```
他會輸出 '函式表達式' 因為**創造階段函式優先**，將以上分解
```javascript=
// 創造階段
var hello;
function hello() {
    console.log("函式陳述式");
}
// 執行
hello = function () {
    console.log("函式表達式");
};

hello(); // 函式表達式
```
### 範例3
再看看這個範例
```javascript=
// 以下輸出 undefined
hello();
function hello() {
    console.log(text);
}
var text = "Hello World";
```
將範例依照上面所說邏輯拆解，就可以看到在函式呼叫時，還未將text賦予Hello World，所以會輸出undefined
```javascript=
// 創造階段
function hello() {
    console.log(text);
}
var text;

// 執行
hello(); // undefined
text = "Hello World";
```
### 範例4

看到可能會想說怎麼不是先輸出'我是第一個函式'再輸出'我是第二個函式'
```javascript=
function hello() {
    console.log("我是第一個函式");
}
hello(); // 我是第二個函式
function hello() {
    console.log("我是第二個函式");
}
hello(); // 我是第二個函式
```
來將上述範例分解，可以看到輸出'我是第一個函式'的函式被覆蓋掉了，所以都會輸出相同內容
```javascript=
// 創造階段
function hello() {
    console.log("我是第一個函式");
}
function hello() {
    console.log("我是第二個函式");
}

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