---
# System prepended metadata

title: var、let、const 的差別

---

var、let、const 的差別
===

### 為什麼要宣告變數?

- 當沒有用var宣告時這個a稱為全域屬性，也就是存在於全域環境(window)下的一個屬性，不僅會汙染全域環境，而且用delete運算子可以隨意刪除，所以這也就說明了為什麼要宣告變數
```javascript=
//已下會造成a可以隨意存取修改，如果程式碼很多這種code會造全域環境汙染變得很亂難以維護
function fnA(){
    a = 0;
}
fnA();
...
...
...
經過好幾千行後
...
function fnB(){
    a = 1;
}
fnB();
console.log(a); // 1
```

### 變數宣告

#### JavaScript在ES6前都用var宣告變數，在ES6開始新增了兩個let、const

- var可以重複宣告、let不能重複宣告
```javascript=
var a = 0;
var a = 1;
console.log(a); // 1

let b = 0;
let b = 1; //已經被宣告了，Uncaught SyntaxError: Identifier 'b' has already been declared
console.log(b);
```

- var可以在window下找到變數、let不能在window下找到變數
```javascript=
var a = 0; //找得到，有值 0
let b = 0; //找不到，但也有值 0
```

- 我們先在全域環境(window)說明有宣告和沒宣告的差別
```javascript=
a = 0; //沒宣告的稱為屬性
var b = 1; //有宣告的稱為變數

delete window.a; //屬性可以被刪除
delete window.b; //變數不能被刪除

console.log(window.a); // undefined，已經被刪除
console.log(window.b); // 1，不能刪除
```

- var宣告的變數屬於函式作用域(function scope)，如果使用函式以外的作用域，也就是區塊作用域(block scope)，就會變成全域變數，造成汙染全域環境
```javascript=
//var只在函式內宣告時不會跑出函式作用域
function fn(){
    var a = 0;
    console.log(a); // 0
}
fn();
console.log(a); // Uncaught ReferenceError: a is not defined

//但在函式以外的作用域則會變成全域變數(if、for....其他)，會造成汙染全域環境
if(false){
  var b = 1;  
}
console.log(b); // undefined，由於b提升到if(block scope)外部所以讀取得到
```
- let、const宣告的變數屬於區塊作用域(block scope)，也就是只要在中誇號內宣告'{ }'，作用域只會存在於中誇號'{ }'內部
```javascript=
//改成用let宣告跟var宣告一樣不會跑出函式作用域
function fn(){
    let a = 0;
    console.log(a); // 0
}
fn();
console.log(a); // Uncaught ReferenceError: a is not defined

//改成用let宣告時只會存在於block scope內，這樣就不回會汙染全域了
if(false){
  let b = 1;  
}
console.log(b); // Uncaught ReferenceError: b is not defined
```

- let、const 暫時性死區(Temporal Dead Zone，TDZ)，其實let及const也有提升的概念，但是他還有另一個概念就是「暫時死區」，如果再宣告前變數前使用此變數就會出現錯誤，所以我們必須手動將變數提升到作用域最上面

```javascript=
function todo(){
    console.log(a); //TDZ，Uncaught ReferenceError: Cannot access 'a' before initialization
    let a = 2;
    console.log(a);
}

todo();
```

- 另外說一下const「常數」，不變的數值（例如圓周率）。
1. 宣告時就要同時賦值，不然會報錯！
1. 賦值後就不能被更動了！

### 結論
#### ES6開始避免使用var，請改成使用let、const，做好全域變數及作用域變數的管理
![](https://i.imgur.com/lqdaMQi.png)


