---
# System prepended metadata

title: var、let、const 的差異
tags: [note, Javascript]

---

# var、let、const 的差異
###### tags: `Javascript` `note`

普遍來說，要分辨 **var、let 、const**  之間的差異我們會先將他們分成兩類，var 跟 let、const。
這兩類的主要差別是**作用域**，我們來看看 MDN 怎麼說明。

####  [var](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var)
>The **`var` statement** declares a ***function-scoped*** or ***globally-scoped*** variable, optionally initializing it to a value.

function-scoped 就是指作用在 function 內，所以離開了 function 你就沒辦法直接存取到（說沒辦法直接存取的原因是，我們可以利用 Closure 特性拿取值），而 globally-scoped 就是我們常見的最外層

```js
var a; // globally-scoped

function foo(){
  var b; // function scoped
}
```

#### [let](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let)
>The **`let`** declaration declares a ***block-scoped*** local variable, optionally initializing it to a value.

什麼是 block-scoped ？簡單說明的話就是在大括號內都是 block-scoped ，所以 function-scoped 跟 globally-scoped 也算在 block-scoped 範疇內，但經常會拿出來說明的有 for loop、while loop、if statement。

```js
for(let i = 0; i < 10; i++){ // blcok-scoped
  let a; 
}

while(true){ // blcok-scoped
  let b 
}

if(true){ // blcok-scoped
  let c;
}
```

但除了 for loop、while loop 這些，還有一種我為了讓複雜計算易於閱讀把它分區塊計算嘗試過的方法。

```js
function foo(){

  // block-scoped
  {
    let a; 
    // ...
  }
	
  // block-scoped
  {
    let b; 
    // ...
  }

}
```

這是可以運作的，但後來因為這樣其實沒有比較好用，所以後來放棄改用一般 function，會想這樣做的原因是 Rust 帶給我的啟發，在 Rust 這可以作為一個**表達式**(expression)，可以回傳值，但是 JS 不行！所以可以用 IIFE（立即函式）作代替。

```rust
fn main(){
  let a = {
      // ...
      20
  };
   
  println!("{}", a); // 20
}
```

#### [const](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)
>Constants are ***block-scoped***, much like variables declared using the [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) keyword. The value of a constant can't be changed through ***reassignment*** (i.e. by using the [assignment operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment)), and it can't be redeclared (i.e. through a [variable declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#declarations)). However, if a constant is an [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) or [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) its properties or items can be updated or removed.

const 跟 let 基本一樣，區別在於 const 不能**重新賦值**（reassignment），但是如果 const 是一個 object 或 array，可以對內部資料進行修改。

能這樣做的原因是我們並沒有對變數本身做**重新賦值**的動作，所以變數本身的**參考**（reference）並沒有變。

```js
const a = {
  value: 10
};
a.value = 20;

console.log(a.value); // 20

const b = [0, 1];

b.push(2); // or b[0] = 4;

console.log(b); // [0, 1, 2]

a = 20; // ❌  reassignment
b = "string"; // ❌  reassignment
```

---
### Hoisting
我們也時常用 hoisting 來區分之間的差異，但是要知道的是 let、const 也有 hoisting，只是行為有點不同罷了，詳細可以參考 [What is hoisting](https://hackmd.io/@FizzyElt/what-is-hoisting)。