Skip to main content

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. 總結

特性varletconst
作用域全域/函式作用域區塊作用域區塊作用域
重新賦值不可(物件/陣列內容可改)
提升提升,初始為 undefined提升,但有 TDZ提升,但有 TDZ
建議使用避免使用需要重新賦值時預設使用,確保不變性