定義變數以及常數的方式。
在認識到這兩個宣告方式前,偶爾會因為全域變數被污染到而傷腦筋,但在使用了它們之後,再也不會遇到這樣的問題了,以下會分析這三種作用域的不同之處,並於後面詳細示範。
var
:
- 函式作用域:只能以函式作為分界線,如放在判斷式或迴圈等語句中,仍然會暴露到全域範圍中。
let、const
:
- 區塊作用域:只在一個
{}
內產生影響,較不易出錯。
# 作用域:
var
:
function demo() {
var a = 10;
}
if (true) {
var b = 20;
}
console.log(a); // a is not defined
console.log(b); // 20
因var
只會被函式區隔作用域,所以變數b
一樣能從外部存取的到。
let、const
:
function demo() {
let a = 10;
}
if (true) {
const b = 20;
}
console.log(a); // a is not defined
console.log(b); // b is not defined
作用域只在{}
區塊內,較不易發生錯誤。
# 提升:
var
:
console.log(a); // undefined
var a = 5;
undefined
也是一個值,表示已經被定義但尚未賦值。
let、const
:
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 10;
console.log(b); // Uncaught ReferenceError: Cannot access 'b' before initialization
const b = 20;
這會丟出錯誤訊息,是 ES6 規定給let、const
的暫時性死區,讓變數提升的情況不會出現,減少運行上的錯誤。
# 定義:
var
:
var a = 5;
var a = 10;
console.log(a); // 10
被重新宣告或重新賦值皆是允許的。
let
:
let a = 5;
let a = 10;
console.log(a); // Uncaught SyntaxError: Identifier 'a' has already been declared
透過let
宣告的變數,無法再次進行宣告。
let a = 5;
a = 10;
console.log(a); // 10
賦予新的值是可以的。
const
:
const a = 5;
const a = 10;
console.log(a); // Uncaught SyntaxError: Identifier 'a' has already been declared
透過const
宣告的常數,無法再次進行宣告。
const a = 5;
a = 10;
console.log(a);
無法賦予新的值。
const a = {};
a.demo = 'test';
console.log(a); // {demo: "test"}
const b = [];
b[0] = 'test';
console.log(b); // ["test"]
如果今天宣告的值是物件或陣列,裡面的值是可以改變的。
# 實例:
var
:
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
這是一個經典的題目,當一秒後會得到五個 5 被打印出來,因為全域變數i
最後被賦予的值就是 5。
let
:
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // 0 1 2 3 4
}, 1000);
}
由於區塊作用域造成的結果,在每次的for
迴圈執行時,用let
宣告的變數都會重新綁定一次。
const
:
for (const i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // 0
}, 1000);
}
只會印出第一個 0,接著會出現Uncaught TypeError
,因為const
的值是不能被重複賦予的。