# 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)。