var
var 的宣告屬於 全域變數,代表 全域物件的屬性。
for (var i=0; i<3; i++) {}
console.log(i) // 3
假設一個 for 迴圈用 var 宣告 i,在全域還是可以取得 i 值。
如果想要限制 i 的作用域的話,可以使用立即函式,避免外層取到 for 迴圈裡面的值,最直接的方式就是使用 let 宣告。
(function () {
for (var i=0; i<3; i++) {}
})()
console.log(i) // i is not defined
---
for (let i=0; i<3; i++) {}
console.log(i) // i is not defined
在 JavaScript 中,var 的作用域是函式作用域,但在函式內的區域變數也可能被視為全域變數,傳統用 var 宣告變數可能會汙染全域,如果使用 let、const 就可以避免這種情形。
if (true) {
var a = 10
}
console.log(a) // 10
console.log(window.a) // 10
let
let 的作用域屬於區塊內({} 大括號),和 const 最大差異就是可以重新賦值,而 const 不行。
let a = 0
{
let a = 1 // 因為 let 的作用域是區塊內,所以不算重複宣告
a = 2
console.log(a) // 2
}
console.log(0) // 0
舉個非同步 for 迴圈的例子,假設想要讓 setTimeout 依序執行並印出結果,如果用 var 宣告的話,因為 var 是全域變數,所以只會取出最後一次執行的結果。
而 setTimeout 是非同步程式,會先放到「事件佇列」裡面,等到所有程式碼執行完畢後才會執行。
如果想要達到預期結果,只要用 let 宣告就可以依序執行並取得正確數值。
for (var i=0; i<3; i++) {
setTimeout(function () {
console.log(`這是第 ${i} 次執行結果`)
}, 0)
} // 這是第 3 次執行結果
---
for (let i=0; i<3; i++) {
setTimeout(function () {
console.log(`這是第 ${i + 1} 次執行結果`)
}, 0)
}
// 這是第 0 次執行結果
// 這是第 1 次執行結果
// 這是第 2 次執行結果
const
const 是宣告一個常數,用 const 宣告的變數沒辦法再被調整。
雖然變數沒辦法被調整,但如果是物件的話,因為物件屬於傳參考特性,只要不直接替換掉物件,可以修改內容屬性值。
const person = {
name: '小明',
money: 500
}
person.name = '大明'
console.log(person.name) // 大明
---
person = {}
console.log(person) // Assignment to constant variable.
Hoisting 與 暫時性死區
JavaScript 中有 hoisting 的現象,先來比較一下這三種的狀況:
console.log(a) // undefined
var a = 1
---
console.log(b) // b is not defined
let b = 2
---
console.log(c) // Cannot access 'c' before initialization
const c = 3
var:undefined,有 hoistinglet:not defined,沒有 hoistingconst: 宣告前無法使用,沒有 hoisting
看起來沒什麼問題,接著猜測一下面範例結果:
- (1) 如果
let沒有提升的話,就會往外層查找取得 小明 的值 - (2) 如果
let有提升的話,就會出現其他狀況
let Ming = '小明'
{
console.log(Ming)
let Ming = '大明'
}
結果是(2): Cannot access 'Ming' before initialization
let 在提升的過程中會產生一個「暫時性死區」Temporal Dead Zone(TDZ)。
在這個區域內是無法存取變數,也就不會賦予 undefined 的值,如果試圖取值就會跳出錯誤提示。
所以 let 雖然有類似提升 創造 - 執行階段 的概念,但是和 var 的 hoisting 概念並不相同。
let Ming = '小明'
{
// 創造
let Ming // 暫時性死區 TDZ
// 執行
console.log(Ming)
let Ming = '大明'
}
重點整理
| 作用範圍 | 重複宣告 | 重新賦值 | Hoisting | |
|---|---|---|---|---|
| var | 全域 | v | v | v |
| let | 區塊 | x | v | v |
| const | 區塊 | x | x | x |


