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)