---
# System prepended metadata

title: '**Hoisting**'

---

# **Hoisting**

看了很多文章說明，但還是沒有很懂Hoisting的基本概念，想自己梳理順過一次把理解的內容整理出來，再麻煩大家來找碴。

在學JavaScript時，很常耳提面命**宣告記得擺在前面**，主要是因為變數、函式在**宣告後會先建立一個記憶體空間**，等到要執行時再將值、函式放入，養成這樣的習慣就能避免一些錯誤資訊的出現。但是不這麼做呢？有時候程式還是跑得動，這時就會遇到Hoistng的問題！

Hoistng的概念以下簡單一句話輕鬆帶過，但是細細咀嚼發現疑問一直冒出來。

> *Hoistng是JavaScript將**宣告**移到頂端的默認行為。*
*在JavaScript中，變數可以在使用後宣告。換句話說，變數可以在宣告之前使用。—W3school*
> 

### 變數與Hoisting

當程式中完全沒有任何宣告，直接執行變數，會以下出現錯誤訊息「carName is not defined」，**尚未被定義**。
```javascript=
console.log(carName);//出現Uncaught ReferenceError: carName is not defined
```
---

> *JavaScript **僅提升宣告**的部分，而不是初始化。如果在使用該變數後才宣告和初始化，那麼該值將是 undefined。—MDN*
> 

如果在`console.log()`後進行宣告，並不會跳出錯誤而是會出現`undefined`。表示現在carName這個變數在記憶體中有個位置，只是目前沒有值。

console.log(carName);
var carName = "Volvo"

由於程式是由上至下一行一行慢慢跑，所以上圖在執行時，因為Hoisting特性把變數carName**宣告**提升到最前面，注意只有宣告，初始化(賦值”Volvo”)的部分並不會一同提升，所以可以理解上圖程式跑的邏輯如下：

```javascript=
var carName;//宣告  //undefined
console.log(carName);//undefined
carName = "Volvo";//初始化、賦予值
```


---

> *Hoisting也適用於其他型別和變數。變數可以在宣告之前進行初始化和使用。但如果沒有初始化，就不能使用它們。—MDN*
> 

```javascript=
//#範例一
var x = 1; // 初始化 x
console.log(x + " " + y);  // '1 undefined'
var y = 2;

//#範例二
var a = 1; // 初始化 a
var b; // 宣告 b
console.log(a + " " + b);  // '1 undefined'
b = 2; // 初始化 b

//#範例三
var c = 1; // 初始化 c
d = 2; // 初始化 d
console.log(c + " " + d);  // '1 2'
var d; // 宣告 d
```

範例一中，y的宣告及初始化都在`console.log`之後才，宣告因hoisting提前可以使用，但尚未初始化所以出現`undefined`，範例二的b其實就是y的程式運行邏輯。再來看到範例三，如果初始化是在`console.log`之前，宣告雖然在後面但會因為hoisting而提前，且d已經初始化，所以`console.log`可以順利顯示「1 2」。

關於hoisting還有temporal dead zone、函式提升等觀念，之後有時間再補上。