JavaScript 開發必知:var 和 let 的區別,你真的了解嗎?
在 JavaScript 的發展過程中,變量聲明方式經歷了從 var 到 let(以及 const)的演變。var 是 ES5 及之前版本中唯一的變量聲明關鍵字,而 let 和 const 是在 ES6(ECMAScript 2015)中引入的。理解 var 和 let 的區別對于編寫高質量、可維護的 JavaScript 代碼至關重要。本文將詳細探討它們之間的差異,并通過具體的代碼示例進行說明。
一、作用域不同
1. var 的函數作用域
var 聲明的變量具有函數作用域(function scope),這意味著在函數內部聲明的變量在整個函數內部都是可訪問的,無論變量是在哪里聲明的。如果在函數外部聲明 var 變量,它將具有全局作用域。
function varExample() {
if (true) {
var x = 10;
}
console.log(x); // 輸出: 10,因為 var 是函數作用域
}
varExample();
// 全局作用域中的 var
var y = 20;
function anotherFunction() {
console.log(y); // 輸出: 20,因為 y 是全局變量
}
anotherFunction();
2. let 的塊級作用域
let 聲明的變量具有塊級作用域(block scope),塊級作用域由一對大括號 {} 定義,例如 if 語句、for 循環、while 循環等。在塊級作用域內聲明的 let 變量僅在該塊及其子塊中可訪問。
function letExample() {
if (true) {
let z = 30;
console.log(z); // 輸出: 30
}
// console.log(z); // 報錯: ReferenceError: z is not defined,因為 z 是塊級作用域變量
}
letExample();
// 全局作用域中的 let(不推薦,應盡量減少全局變量)
let a = 40;
function yetAnotherFunction() {
console.log(a); // 輸出: 40
}
yetAnotherFunction();
二、變量提升不同
1. var 的變量提升
var 聲明的變量會被提升到其所在作用域的頂部,但只會提升聲明,不會提升賦值。這意味著在聲明之前可以訪問 var 變量,但它的值會等于undefined
function varHoistingExample() {
console.log(b); // 輸出: undefined,而不是報錯
var b = 50;
console.log(b); // 輸出: 50
}
varHoistingExample();
2. let 的暫時性死區
let 聲明的變量也會被提升,但不會初始化。在聲明之前訪問 let 變量會導致 ReferenceError,這個區域被稱為暫時性死區:
function letHoistingExample() {
// console.log(c); // 報錯: ReferenceError: Cannot access 'c' before initialization
let c = 60;
console.log(c); // 輸出: 60
}
letHoistingExample();
三、重復聲明不同
1. var 允許重復聲明
在同一個作用域內,可以使用 var 多次聲明同一個變量,后聲明的變量會覆蓋先聲明的變量(但不會報錯,這可能導致意外的行為):
function varRedeclarationExample() {
var d = 70;
var d = 80; // 不會報錯,d 的值變為 80
console.log(d); // 輸出: 80
}
varRedeclarationExample();
2. let 不允許重復聲明
在同一個作用域內,使用 let 多次聲明同一個變量會導致語法錯誤
function letRedeclarationExample() {
let e = 90;
// let e = 100; // 報錯: SyntaxError: Identifier 'e' has already been declared
e = 100; // 這是允許的,是賦值操作,不是聲明
console.log(e); // 輸出: 100
}
letRedeclarationExample();
四、在循環中的應用
1. var 在循環中的問題
由于 var 是函數作用域,在循環中聲明的 var 變量在整個函數內都是可訪問的,這可能導致一些意外的行為。
function varInLoopExample() {
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs.push(function() {
console.log(i);
});
}
funcs[0](); // 輸出: 3
funcs[1](); // 輸出: 3
funcs[2](); // 輸出: 3
// 因為循環結束后 i 的值是 3,所有函數都引用了同一個 i 變量
}
varInLoopExample();
2. let 在循環中的優勢
let 的塊級作用域可以解決上述問題,每次循環都會創建一個新的塊級作用域,每個函數都引用了自己作用域內的 i 變量。
function letInLoopExample() {
var funcs = [];
for (let j = 0; j < 3; j++) {
funcs.push(function() {
console.log(j);
});
}
funcs[0](); // 輸出: 0
funcs[1](); // 輸出: 1
funcs[2](); // 輸出: 2
// 每次循環都創建了一個新的塊級作用域,每個函數引用了自己作用域內的 j 變量
}
letInLoopExample();
五、總結
在現代 JavaScript 開發中,推薦優先使用 let 對于不會重新賦值的變量)來聲明變量,因為它們提供了更嚴格的作用域規則,有助于減少代碼中的錯誤和意外行為。只有在需要兼容舊版瀏覽器或特定場景下才考慮使用 var。