本文 AI 產出,尚未審核

JavaScript – 變數與資料型別:Null、Undefined、NaN


簡介

在 JavaScript 中,變數的值 可能不是實際的資料,而是「沒有值」或「不是數字」的特殊標記。這三個標記—nullundefinedNaN—在日常開發裡經常出現,卻常被新手混淆。
正確掌握它們的意義與使用時機,能避免程式錯誤、提升除錯效率,同時讓程式的邏輯更清晰、可讀性更高。本文將從概念、範例、常見陷阱與最佳實踐,帶你深入了解這三者的差別與實務應用。


核心概念

1. undefined – 「未定義」

  • 何時產生

    1. 變數宣告了但未賦值。
    2. 物件屬性或陣列索引不存在。
    3. 函式沒有 return,或 return 後未寫值。
  • 特性

    • undefined 是一個原始值(primitive),其類型為 undefined
    • nullNaN 不相等(=== 比較會回傳 false)。

範例 1:變數未賦值

let a;
console.log(a);          // => undefined
console.log(typeof a);   // => "undefined"

範例 2:物件屬性不存在

const user = { name: "Alice" };
console.log(user.age);   // => undefined

範例 3:函式未回傳

function doNothing() {}
const result = doNothing();
console.log(result);      // => undefined

2. null – 「空值」

  • 何時使用

    • 明確表示「此處應該有值,但目前是空的」;通常在意圖上比 undefined 更具語意。
    • 常用於初始化變數、清除物件參考、或作為 API 回傳的「無資料」標記。
  • 特性

    • null 也是原始值,但類型是 object(這是 JavaScript 的歷史遺留問題)。
    • undefined 嚴格相等 (===) 為 false,但寬鬆相等 (==) 為 true

範例 4:手動設定為空

let cache = null;               // 尚未載入資料
if (cache === null) {
  cache = fetchData();          // 取得資料後填入
}

範例 5:清除引用

let node = document.getElementById("myDiv");
node = null;                    // 讓垃圾回收器可以回收

3. NaN – 「不是數字」

  • 何時產生

    • 執行數學運算時,結果無法表達為有效的數字。
    • 例如 Number("abc")0/0Math.sqrt(-1) 等。
  • 特性

    • NaN 的類型是 number,但它 不等於自身NaN === NaNfalse)。
    • 必須使用 Number.isNaN()isNaN() 來檢測。

範例 6:字串轉數字失敗

const input = "123abc";
const num = Number(input);
console.log(num);               // => NaN
console.log(Number.isNaN(num)); // => true

範例 7:除以零的特殊情況

console.log(0 / 0);             // => NaN
console.log(Infinity / Infinity); // => NaN

範例 8:不小心傳入非數字

function add(a, b) {
  return a + b;                 // 若 a、b 其中一個是 NaN,結果仍是 NaN
}
console.log(add(5, NaN));       // => NaN

常見陷阱與最佳實踐

陷阱 說明 解法/最佳實踐
undefined 當作 null 兩者在語意不同,直接比較 (===) 會失敗。 依需求明確使用 null(表示「空」)或 undefined(表示「未設定」),避免混用。
NaN==/=== 判斷失效 NaN === NaNfalse,容易造成判斷錯誤。 使用 Number.isNaN(value)(ES6)或 isNaN(value)(舊版)檢測。
自動型別轉換導致 undefined 例如 obj.prop?.method(),如果 propundefined,整個表達式會回傳 undefined 而不是拋錯。 確認使用可選鏈 (?.) 前,已了解其回傳值可能是 undefined,必要時加上預設值 (??).
null 當作物件使用 訪問 null 的屬性會拋出 TypeError 在操作前先檢查 value !== null && typeof value === "object"
未處理 NaN 的算術結果 連鎖運算若出現 NaN,整個結果都會是 NaN,不易追蹤。 在關鍵運算後立即檢查 Number.isNaN(result),或使用 isFinite() 保障結果是有限數字。

建議的程式碼寫法

// 安全取得物件屬性,並提供預設值
const age = user?.profile?.age ?? null;   // 若不存在則回傳 null

// 檢查數值是否有效
function safeDivide(a, b) {
  if (b === 0) return NaN;               // 明確回傳 NaN
  const result = a / b;
  return Number.isNaN(result) ? NaN : result;
}

實際應用場景

  1. API 回傳的空資料

    • 後端可能回傳 null 表示「查無結果」,而非 undefined。前端收到後,應以 === null 判斷並顯示「無資料」訊息。
  2. 表單驗證

    • 使用者未填寫欄位時,表單資料物件的屬性可能是 undefined。驗證時可統一將 undefined 轉為 null,簡化後續判斷。
  3. 數學運算與圖表繪製

    • 資料點若產生 NaN,圖表函式庫(如 Chart.js)通常會跳過該點。開發者需要在資料清理階段使用 Number.isNaN() 过滤或替換為 null,避免圖表斷裂。
  4. 記憶體釋放與資源回收

    • 當大型物件不再使用時,將變數設為 null,有助於垃圾回收器更快回收記憶體,提升效能。
  5. 條件式的預設值

    • 使用 ??(Nullish Coalescing)運算子,僅在值為 nullundefined 時提供預設值,避免 0""false 被誤判為「空」。
const limit = config.maxItems ?? 10;   // 若 config.maxItems 為 null/undefined,使用 10

總結

  • **undefined** 代表「尚未被賦值」或「不存在的屬性」,通常是系統自動產生。
  • **null** 則是開發者主動設定的「空」值,用來明確表示「此處應有資料,但目前沒有」。
  • **NaN** 表示「不是一個有效的數字」,在數學運算失敗時產生,且必須透過 Number.isNaN() 檢測。

掌握這三者的差異與正確的判斷方式,能讓你在撰寫 JavaScript 程式時,減少意外錯誤、提升除錯效率,同時寫出更具語意與可維護性的程式碼。未來在面對 API 整合、資料驗證或數值運算時,請依照上述最佳實踐來處理 nullundefinedNaN,讓你的程式更穩健、更易讀。祝你寫程式愉快!