本文 AI 產出,尚未審核

JavaScript 運算子教學:比較運算子 == vs ===


簡介

在 JavaScript 中,比較運算子是日常開發不可或缺的工具。它們負責判斷兩個值之間的關係,進而決定程式流程的走向。特別是 ==(相等)===(嚴格相等),雖然寫法相近,卻在背後執行的邏輯上大相逕庭。

對初學者而言,誤用 == 常會導致 隱藏的型別轉換(type coercion)問題,進而產生難以偵測的 bug。相反地,熟練掌握 === 的使用方式,能讓程式的行為更可預測、可維護。本文將深入探討兩者的差異、實作範例、常見陷阱與最佳實踐,幫助你在實務開發中正確選擇比較運算子。


核心概念

1. 基本語意

運算子 含義 會不會自動型別轉換?
== 相等(抽象相等) ,會嘗試將兩側的值轉成相同型別再比較
=== 嚴格相等(嚴格相等) 不會,只有在型別與值都相同時才回傳 true

重點=== 同時檢查 型別== 只檢查 ,但在比較前會先進行型別轉換。


2. == 的型別強制轉換規則(簡化版)

  1. 數字 vs 字串:字串會被轉成數字再比較。
    "5" == 5   // true,字串 "5" 轉成數字 5
    
  2. 布林 vs 其他:布林會先轉成 0(false)或 1(true),再與右側比較。
    false == 0 // true
    true  == 1 // true
    
  3. null 與 undefined:只有 null == undefinedtrue,與其他任何值比較皆為 false
    null == undefined // true
    null == 0          // false
    
  4. 物件 vs 原始值:物件會先呼叫 valueOftoString 取得原始值,再與右側比較。
    [1,2] == "1,2" // true,陣列轉成字串 "1,2"
    

3. === 的行為

  • 不會 進行任何型別轉換。
  • 只有當 左、右兩側的型別相同,且 值相等 時,才回傳 true
5 === "5"   // false,型別不相同
null === undefined // false

4. 為什麼建議預設使用 ===

  1. 可預測性:程式碼的行為不會因為隱藏的型別轉換而改變。
  2. 維護成本低:未來同事或自己回顧程式時,能立即看出比較的意圖。
  3. 避免奇怪的 bug:例如 [] == falsetrue,但 [] === falsefalse,前者往往不是開發者的預期。

程式碼範例

以下示範 5 個常見情境,說明 ===== 的差異與正確的寫法。每段程式碼皆附上中文註解。

範例 1:字串與數字的比較

// 使用 == 時,字串會被轉成數字
console.log("10" == 10);   // true

// 使用 === 時,型別不同直接回傳 false
console.log("10" === 10);  // false

// 正確做法:若想比較值相等,先手動轉型
console.log(Number("10") === 10); // true

範例 2:nullundefined 的相等性

// 只在 == 時相等,=== 永遠不相等
console.log(null == undefined);   // true
console.log(null === undefined);  // false

// 在判斷「是否為空」時,建議使用嚴格相等
function isEmpty(value) {
  return value === null || value === undefined;
}
console.log(isEmpty(null));       // true
console.log(isEmpty(undefined));  // true

範例 3:布林值與其他類型的隱形轉換

// == 會把布林值轉成 0 / 1 再比較
console.log(false == 0);   // true
console.log(true == "1");  // true

// === 不會自動轉型
console.log(false === 0);  // false
console.log(true === "1"); // false

// 建議:先將左側值轉成布林,再比較
console.log(Boolean(0) === false); // true

範例 4:陣列與字串的比較

// 陣列會被自動呼叫 toString(),變成逗號分隔的字串
console.log([1, 2, 3] == "1,2,3"); // true
console.log([1, 2, 3] === "1,2,3"); // false

// 若要比較內容相等,應自行比較每個元素
function arraysEqual(a, b) {
  return a.length === b.length && a.every((v, i) => v === b[i]);
}
console.log(arraysEqual([1,2,3], [1,2,3])); // true

範例 5:物件與原始值的比較

const obj = {
  valueOf() { return 42; }   // 當做原始值使用時會回傳 42
};

console.log(obj == 42);   // true,會呼叫 valueOf()
console.log(obj === 42);  // false,型別不同

// 正確的做法:顯式取得原始值再比較
console.log(obj.valueOf() === 42); // true

常見陷阱與最佳實踐

陷阱 說明 解決方式
隱式型別轉換 == 會自動把字串、布林、物件等轉型,導致意外相等。 預設使用 ===,必要時手動轉型(Number(), String(), Boolean())。
nullundefined 混用 null == undefinedtrue,但在大多數情況下兩者的語意不同。 明確檢查 value === nullvalue === undefined,或使用 value == null 只在「任意空值」的情境下。
空陣列/空字串與布林的比較 [] == false"" == false 都會回傳 true,容易誤判。 使用 Array.isArray()typeof=== 進行嚴格比較。
NaN 的比較 NaN == NaNNaN === NaN 都是 false 使用 Number.isNaN(value) 判斷。
浮點數精度 0.1 + 0.2 === 0.3false,因為浮點數誤差。 使用容差比較(Math.abs(a - b) < EPSILON)。

最佳實踐清單

  1. 統一使用 ===,除非確定需要 == 的寬鬆比較。
  2. 在條件判斷前先正規化型別(例如 String(id)Number(age))。
  3. 編寫 lint 規則:如 ESLint 的 eqeqeq 規則,強制使用嚴格相等。
  4. 避免在 if 內直接比較物件,改用自訂的比較函式。
  5. 對於可能是 nullundefined 的值,使用 可選鏈?.)或 空值合併??)避免意外錯誤。

實際應用場景

1. 表單驗證

在前端表單驗證時,使用者輸入的值大多是 字串。若要檢查是否為空或符合特定數值,必須先轉型:

function isAdult(ageInput) {
  const age = Number(ageInput);   // 明確轉成數字
  return age >= 18;               // 直接比較,使用嚴格相等不涉及
}

2. API 回傳值檢查

後端 API 可能會回傳 nullundefined 或空字串。使用 === 可以明確區分:

fetch('/api/user')
  .then(res => res.json())
  .then(data => {
    if (data.username === null) {
      console.warn('使用者名稱未設定');
    } else if (data.username === undefined) {
      console.error('API 回傳結構異常');
    } else {
      console.log(`Hello, ${data.username}`);
    }
  });

3. 資料結構的 key 判斷

在物件或 Map 中查找鍵時,必須使用嚴格相等,否則可能得到錯誤結果:

const map = new Map();
map.set(1, 'one');
map.set('1', 'string one');

console.log(map.get(1));   // 'one'
console.log(map.get('1')); // 'string one'

如果不小心使用 ==,會把 1'1' 混為一談,造成資料錯亂。

4. 測試斷言(unit test)

測試框架(如 Jest)建議使用 toBe(嚴格相等)而非 toEqual(深度相等)來檢查原始值:

test('strict equality', () => {
  expect(5).toBe(5);          // 嚴格相等
  expect('5').not.toBe(5);    // 不相等
});

總結

  • == 會在比較前執行型別強制轉換,容易產生「看似相等」卻實際不符合預期的情況。
  • === 不做任何型別轉換,只有在 型別 完全相同時才回傳 true,因此是 預設的安全選擇
  • 在日常開發中,養成使用 === 的習慣,配合手動型別轉換或工具(如 ESLint)可大幅降低 bug 風險。
  • 了解兩者的底層機制,才能在特殊需求(例如寬鬆的 null/undefined 判斷)時,正確且安全地使用 ==

掌握比較運算子的細節,不只是寫出「能跑」的程式,更是打造 可讀、可維護、可靠 程式碼的關鍵。祝你在 JavaScript 的旅程中,能以嚴謹的比較邏輯,寫出更健壯的應用程式!