const宣告的變數是區塊級別的宣告,一開始就要設定初始值,在存在的scope中不能再重新賦值。
與let比較
const跟let非常的相似,它們的相似之處在於宣告區塊的相關特性,總共有下面三項:
- 宣告變數會是區塊級別。
- 在相同區塊下禁止重複宣告。
- 相同區塊下,在未宣告前的行數,此變數都是在Temporal Dead Zone(TDZ)中。
上面三點在JavaScript的Hoisting一文中已有詳細說明,我們以下面幾個例子再來回想上面所述的特性。
區塊級別
1 | const a = 'global'; |
在if區塊內的a跟全域中的a因為區塊不同而被宣告為不同的變數,因此這樣的動作是合法的。
禁止重複宣告
1 | const a = 'global'; |
在最後一行用var宣告的a因為跟global的a都同在全域中,因此這次會拋出SyntaxError的錯誤。
TDZ
1 | // TDZ |
在TDZ中為了跟未宣告變數作區別,所以在TDZ中使用typeof也會拋出ReferenceError。
const的特性
不可重複賦值
const所宣告的變數本身有不可重複賦值的特性:
1 | const a = "global"; |
- 第一次的
reassign因在同一個區塊中,所以因為const不可重複賦值的特性而拋出TypeError。 - 在
if區塊中的第二次reassign雖然區塊不同,但因為if區塊內並沒有宣告a,所以會向上一層區塊找尋,找到的就是const的a變數,因此還是拋出TypeError。
物件中的內容可以改變
1 | const arr = []; |
這個例子以Array及Object為例,我們可以看到arr用push增加元素或是obj改變name都不會拋出例外,但是對於const物件本身做修改的話就會出錯。
迴圈中的const
現在我們知道const是一個不可以重新賦值的變數,那它可以用在迴圈中嗎? 我們看看下面的例子:
1 | for (const i = 0; i < 10; i++) { |
看這個例子會發現,在第一次巡覽時(i=0)是正確的,會輸出0,但是在第二次巡覽時因為i++試圖改變const變數,所以拋出了例外。
上面的例子我們知道const不能用在for中,那for of呢?
1 | var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; |
因為for of會在每次巡覽中重新宣告一個新的const i變數,因此每次的巡覽都是不同的變數,也沒有像i++這樣改動const變數,所以只要在for區塊內沒有動到i變數就會是合法的操作,所以for of及for in對const來說都是合法的動作。
比較表
綜合之前JavaScript的var陳述式及JavaScript中的Let的介紹,我們可以整理成兩張表格,一張是非區塊級別宣告及區塊級別宣告的差異,另一張是let及const的差異。
非區塊級別宣告(var) vs 區塊級別宣告(let/const)
這裡以作用域、重複宣告及全域的特性做比較。
| var | let/const | |
|---|---|---|
| Scope | Hoisting | Block Bindings(TDZ) |
| Redeclaration | Yes | No |
| Global | Yes | No |
let vs const
這裡以初始化及重複賦值的兩個特性做比較。
| let | const | |
|---|---|---|
| Initialization | Optional | Necessary |
| Reassign | Yes | No(except value of objects) |
結語
const宣告變數本身是區塊級別的宣告,跟let一樣也有不能重複宣告的特性,而其自身有不能重新賦值但物件的內容可以重新賦值的特性,在宣告常數量時非常好用,我們也在文末做了var、let及const的區別比較圖,幫助我們更容易了解三者的差異。