Skip to main content

變數宣告 var/let/const

在 JavaScript 裡面有三種宣告變數的方式,主要的差別在於變數的 scope 與是不是能夠重新賦值。

varletconst
scopefunctionblockblock
是否能重新賦值OOX
hoistingOOO
TDZXOO

var#

var 的 scope 是 function,所以就算在 if else 裡面宣告,在外面也能存取這個變數。但只要超過 function 外就不行。

function test() {
if (true) {
var a = 1
}
console.log(a) // 1,因為 a 的 scope 是 test
}
test()
console.log(a) // 超出範圍,ReferenceError: a is not defined

let#

與 var 類似,但 scope 侷限在 block。舉例來說,在 if else 裡面宣告時就只能在那裡面使用。function 也算是一種 block,所以底下 b 的 scope 就是 test function,超出範圍就無法存取。

function test() {
let b = 2
if (true) {
let a = 1
}
// ReferenceError: a is not defined
// a 的 scope 是上面那個 if block
console.log(a)
}
test()
// ReferenceError: b is not defined
// b 的 scope 是 test function
console.log(b)

const#

與 let 類似,scope 一樣是 block,差別在於是否能重新賦值,以及 const 一定要宣告初始值。

// Uncaught SyntaxError: Missing initializer in const declaration
const a
const b = 1
// Uncaught TypeError: Assignment to constant variable.
b = 3

雖然 const 確實是 constant(常數)的簡寫,但會一直強調「重新賦值」而非「常數」,是因為如果變數是 reference type 的話,是可以修改到參照的物件的。

const a = {name: 'peter'}
// 這行不會有任何錯誤,但從某個角度來看 a 確實改變了
a.name = 'nick'

如果想真的阻止物件被修改,請使用 Object.freeze

關於 hoisting 跟 TDZ 的解釋可以參考:我知道你懂 hoisting,可是你了解到多深?