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
的區別比較圖,幫助我們更容易了解三者的差異。