0%

ES6-let與const

let與const可以視為取代var來定義變數與常數的方法,javascript過去只有var的語法,定義的也只有變數,而並沒有常數這個概念,並且不小心就會洩漏到全域。

var-作用域為函式作用域(function scope)

let、const-作用域為一個區塊作用域(block scope)

let

過去我們若利用var在function中宣告變數,則此變數就會只存在function中,並不會變成全域變數,但若在if、while、for這些區塊語法中,就會變成全域變數。

1
2
3
4
if(true){
var i = 3
}
console.log(i) //洩漏到全域中所以會顯示3

甚至在for迴圈裡面宣告條件的變數也會洩漏到全域中

1
2
3
for(var i=0;i<3;i++){
}
console.log(i) //洩漏到全域中所以會顯示3

使用let來宣告變數的話就可以防止這樣的情況發生,因為let的作用域是block,block包括了function、If、else、for、while…等。只要是大括號{}裡面包裹起來的程式碼,都是區塊作用域。所以使用了let來替代var宣告變數

跟上面var在區塊作用域比較,使用let的方法來宣告可以讓變數只存在於區塊內

1
2
3
4
if(true){
let i = 3
}
console.log(i) //不會顯示出來,因為找不到i

在for迴圈裡面利用let宣告也可以防止條件變數洩漏到全域去

1
2
3
for(let i=0;i<3;i++){
}
console.log(i) //不會顯示出來,因為找不到i

for迴圈中的let

以下面的例子為例,在for迴圈中使用setTimeout來延遲console.log的時間,在執行後發現印出來的結果跟預期的不同,本來預期應該是要”這是第1次執行”、”這是第2次執行”、”這是第3次執行”,但執行出來卻都是”這是第4次執行”。
會發生這樣的問題是因為,透過了var來宣告的時候,for迴圈將會不斷的將i累加上去,所以當setTimeout時間到了要執行的時候,得到的結果就是最後i累加完的最後結果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for(var i=1;i<4;i++){
console.log(i)
setTimeout(function () {
console.log('這是第' + i + '次執行');
}, 10);
}

//結果將會是
//1
//2
//3
//這是第4次執行
//這是第4次執行
//這是第4次執行

但如果是透過let來宣告時,就可以達到預期的運行結果,那為什麼會這樣呢?主要是因為使用let宣告變數,let的作用域是區塊作用域,每次for迴圈每次的執行,都會重新綁定變數(re-bind),這樣就可以確保迴圈每次執行時,變數都是獨立的,並且不會互相影響。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for(let i=1;i<4;i++){
console.log(i)
setTimeout(function () {
console.log('這是第' + i + '次執行');
}, 10);
}

//結果將會是
//1
//2
//3
//這是第1次執行
//這是第2次執行
//這是第3次執行

const

const就是常數,透過const來宣告必須在一開始就給定值,與let、var不同的地方就是它在宣告之後就不能再重新指定( re-assignment)了,若再指定值則會發生錯誤

1
2
const i = 5
i = 10//會發生錯誤,常數不能re-assignment

若const宣告的為物件,則物件的內容可以更動,但物件本身並不能重新指定為其他物件,就如同你可以更換車子的零件,但車子本身是不能替換的

1
2
3
4
5
const a={x:0}
c.x=3 //可以re-assignment
console.log(c.x) //顯示為3

c={ 其他內容} //會發生錯誤,不能重新re-assignment成其他物件

Reference:
Day 05: ES6篇 - let與const
ES6 開始的新生活 let, const
神奇的函式作用域