var vs. let vs. const
1. var、let 和 const 的基本概述
這三個關鍵字都用來宣告變數,但它們在作用域 (scope)、重新賦值和提升 (hoisting) 行為上有明顯不同。以下是簡單的總結:
-
var:舊式的變數宣告方式,作用域是全域 (global) 或函式 (function) 作用域,支援重新賦值,會被「提升」到程式碼頂端。
-
let:ES6 引入,支援區塊作用域 (block scope),允許重新賦值,但不會被提升到頂端。
-
const:ES6 引入,也是區塊作用域,但不可重新賦值(物件或陣列的內容仍可修改),同樣不會被提升。
接下來,我會逐一詳細說明這三者的特性,並附上程式碼範例,讓你能實際操作並觀察差異。
2. 詳細比較與程式碼範例
(1) 作用域 (Scope)
-
var:只有全域作用域或函式作用域,在 區塊外仍可存取。
-
let 和 const:支援區塊作用域,在 區塊外無法存取。
程式碼範例:
// var 的作用域範例
function testVar() {
if (true) {
var x = 10;
console.log('在 if 區塊內,x =', x); // 輸出: 在 if 區塊內,x = 10
}
console.log('在 if 區塊外,x =', x); // 輸出: 在 if 區塊外,x = 10
}
testVar();
// let 的作用域範例
function testLet() {
if (true) {
let y = 20;
console.log('在 if 區塊內,y =', y); // 輸出: 在 if 區塊內,y = 20
}
// console.log('在 if 區塊外,y =', y); // 錯誤: y is not defined
}
testLet();
// const 的作用域範例
function testConst() {
if (true) {
const z = 30;
console.log('在 if 區塊內,z =', z); // 輸出: 在 if 區塊內,z = 30
}
// console.log('在 if 區塊外,z =', z); // 錯誤: z is not defined
}
testConst();
說明:
-
var 的變數 x 在函式內的任何地方都可以存取,因為它的作用域是整個函式。
-
let 和 const 的變數 y 和 z 只在 if 區塊內有效,離開區塊後會報錯,因為它們是區塊作用域。
(2) 重新賦值
-
var 和 let:可以重新賦值。
-
const:不可重新賦值,但如果是物件或陣列,內部的屬性或元素可以修改。
程式碼範例:
// var 重新賦值
var a = 100;
a = 200; // 允許重新賦值
console.log('var a =', a); // 輸出: var a = 200
// let 重新賦值
let b = 300;
b = 400; // 允許重新賦值
console.log('let b =', b); // 輸出: let b = 400
// const 重新賦值
const c = 500;
// c = 600; // 錯誤: Assignment to constant variable
console.log('const c =', c); // 輸出: const c = 500
// const 物件的屬性可以修改
const obj = { name: '小明' };
obj.name = '小華'; // 允許修改物件屬性
console.log('const obj =', obj); // 輸出: const obj = { name: '小華' }
// const 陣列的元素可以修改
const arr = [1, 2, 3];
arr.push(4); // 允許修改陣列內容
console.log('const arr =', arr); // 輸出: const arr = [1, 2, 3, 4]
說明:
-
var 和 let 都可以自由重新賦值,適合用在需要變動數值的場景。
-
const 適合用來宣告不會改變的變數(例如常數),但要注意物件或陣列的內部屬性仍然可以修改。
(3) 提升 (Hoisting)
-
var:會被「提升」到程式碼頂端,宣告會提前,但賦值不會。
-
let 和 const:也會被提升,但處於「暫時性死區 (Temporal Dead Zone, TDZ)」,在宣告前存取會報錯。
程式碼範例:
// var 的提升
console.log('提升前,var d =', d); // 輸出: 提升前,var d = undefined
var d = 700;
// let 的提升(但有 TDZ)
try {
console.log('提升前,let e =', e); // 錯誤: Cannot access 'e' before initialization
} catch (error) {
console.log('錯誤訊息:', error.message);
}
let e = 800;
// const 的提升(但有 TDZ)
try {
console.log('提升前,const f =', f); // 錯誤: Cannot access 'f' before initialization
} catch (error) {
console.log('錯誤訊息:', error.message);
}
const f = 900;
說明:
-
var 的提升導致變數在宣告前是 undefined,這可能導致潛在的 bug。
-
let 和 const 的 TDZ 確保你不會在變數宣告前使用它們,程式碼更安全。
3. 什麼時候使用 var、let 和 const?
-
使用 var:
-
幾乎不建議使用,除非你需要支援很舊的瀏覽器(例如 IE)。
-
因為它的作用域和提升行為容易導致 bug,現代 JavaScript 幾乎都用 let 或 const。
-
-
使用 let:
-
當變數的值需要改變時,例如迴圈計數器或臨時變數。
-
範例:
for (let i = 0; i < 5; i++) { ... }
-
-
使用 const:
-
當你希望變數不被重新賦值,例如常數、API URL、或物件/陣列的參考。
-
範例:
const API_URL = 'https://api.example.com';
-
建議:
-
優先使用 const,如果需要重新賦值再改用 let。
-
避免使用 var,因為它的行為不夠直觀且容易出錯。
4. 總結
特性 | var | let | const |
---|---|---|---|
作用域 | 全域/函式作用域 | 區塊作用域 | 區塊作用域 |
重新賦值 | 可 | 可 | 不可(物件/陣列內容可改) |
提升 | 提升,初始為 undefined | 提升,但有 TDZ | 提升,但有 TDZ |
建議使用 | 避免使用 | 需要重新賦值時 | 預設使用,確保不變性 |