[JS] 變數宣告方式:let、const、var
JavaScript 過去只有 var
一種變數宣告方式,直到 2015 年發表的 ECMAScript 2015(ES2015),第 6 版,又被稱為 ECMAScript 6(通常簡稱為 ES6 ),才有 let
和 const
兩種新的變數宣告方式,這個版本有相當多的革新,現在常用的箭頭函式、樣板字串…等都包含在其中。
參考資料: Wiki - ECMAScript
💎 Can I Use?
雖然 2015 年距今已經超過 6 年了,但是仍有些企業或公司在使用 IE 這類過時的瀏覽器,let
和 const
在 IE 11 只有部分支援、 IE 10 以下版本則是完全不支援,如有支援需求就需要搭配 Babel 來轉換成兼容的程式碼。
參考資料: Can I Use
💎 變數宣告方式的差異
var
規範較鬆,有許多小陷阱需要小心使用,let
和 const
有了進一步的規範,可以針對不同需求運用,使用上較安全,兩者間有5個主要的差異在下個段落逐一說明。:
- 可否重複宣告
- 可否重新賦值
- 是否需要初始值
- 作用域的範圍
- 提昇(Hoisting)機制的差異
🔸 1、重複宣告
var
可以重複宣告同一個變數名稱,後者會覆蓋前者,而且程式不會報錯,使用起來較危險,萬一不小心使用了相同的名稱,可能造成其他段落程式碼出錯。1
2
3var a = 1;
var a = 2;
console.log(a); // 2let
和const
不允許重複宣告,使用起來較安全。1
2
3let b = 1;
let b = 2;
// Uncaught SyntaxError: Identifier 'b' has already been declared
🔸 2、重新賦值
如果不知道『常數』是什麼,可以先看一下維基百科的說明。
摘錄自維基百科:
常數,又稱定數(Constant),是指一個數值固定不變的常量,例如圓周率,與之相反的是變數。參考資料: Wiki - 常數
過去只有
var
時,如果想要宣告一個不能被變更的常數,通常會用全部大寫,加上_
連接單字來標示,但是名稱只能幫助辨識,實際操作並不具有常數的限制。1
2
3var DO_NOT_TOUCH_ME = 'X';
DO_NOT_TOUCH_ME = '我偏要改';
console.log(DO_NOT_TOUCH_ME); // 我偏要改ES6 提供的
const
宣告方式可以實際的宣告一個常數,有了const
之後不需要使用大寫格式命名來區別是不是常數,看宣告方式即可(視團隊開發時的規範而定);而let
則是和var
一樣可以重新賦值。1
2
3const doNotTouchMe = 'X';
doNotTouchMe = '我偏要碰';
// Uncaught TypeError: Assignment to constant variable.const
的使用時機:對 JS 新手來說,大概只會想到圓周率、太陽數量…等,在撰寫時遇到下列的情形都建議使用const
宣告。DOM
:使用querySelector
這類方法取得的 DOM 如果被改變,容易造成邏輯混亂,維護困難。陣列
:使用陣列方法來操作,避免被=
賦值給覆蓋掉。物件
:使用物件方法來操作,避免被=
賦值給覆蓋掉。函式表示式
:避免被=
賦值給覆蓋掉。
延伸問題:
使用 const 宣告的變數應該不能被變更才對,為什麼『陣列』和『物件』要使用 const 來宣告?
Ans:
變數裡面存放的陣列和物件並不是實體,而是指向實體的記憶體位置,就像是變數名稱存放了帝寶的地址,透過這個變數名稱的值能到達帝寶的實體位置,對大樓做變更操作。
詳細可以參考我的另一篇文章 參數傳遞方式 Call by what?
🔸 3、初始值
- 常數是不能更動的值,在一開始設定好值也是相當合理,因此
const
在宣告的時候一定要賦予值,var
和let
則無此限制。1
2const a;
// Uncaught SyntaxError: Missing initializer in const declaration
🔸 4、作用域
- 作用域(Scope)是變數可以被使用的區域,也代表著在相同的作用域才會有重複命名的衝突問題,只要作用域不同就可以宣告相同名稱的變數。
var
:函式作用域,只在 function 間區隔作用域,範圍大,不好區分。let、const
:區塊作用域,在 {…}(大括弧)間區隔作用域,範圍小,容易區分。
詳細說明可以參考我的另一篇文章: [JS] 作用域(Scope)與範圍鏈(Scope Chain)
🔸 5、提昇(Hoisting)
- JavaScript 在進入執行階段前會將文件中所有宣告的變數、函式(函式陳述式)提前到最上方,差異如下:
var
:變數提到最上方後會實體化
(寫入記憶體,但尚未賦值),在實際執行到該行變數宣告的程式碼前可以被取用
(取值結果為 undefined)。let、const
:變數提前到最上方後不會實體化
,在實際執行到該行變數宣告的程式碼前不可以取用
(取值結果為 執行階段錯誤),這段不能取用的期間又稱為暫時性死區(TDZ)
。
詳細說明可以參考我的另一篇文章: [JS] 提昇(Hoisting)機制
💎 總結
整理後的變數宣告方式差異列表如下:
var | let | const | |
---|---|---|---|
重複宣告 | ✅ | ❌ | ❌ |
重新賦值 | ✅ | ✅ | ❌ |
強制賦予初始值 | ❌ | ❌ | ✅ |
作用域 | function | { } | { } |
提升機制 | 可被取用 | TDZ | TDZ |
以上是我對變數型別的一點認知,如有錯誤或是補充的知識點,也歡迎大家不吝指教,謝謝!