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,做好全域變數及作用域變數的管理
