本文 AI 產出,尚未審核
JavaScript – 變數與資料型別:Null、Undefined、NaN
簡介
在 JavaScript 中,變數的值 可能不是實際的資料,而是「沒有值」或「不是數字」的特殊標記。這三個標記—null、undefined、NaN—在日常開發裡經常出現,卻常被新手混淆。
正確掌握它們的意義與使用時機,能避免程式錯誤、提升除錯效率,同時讓程式的邏輯更清晰、可讀性更高。本文將從概念、範例、常見陷阱與最佳實踐,帶你深入了解這三者的差別與實務應用。
核心概念
1. undefined – 「未定義」
何時產生:
- 變數宣告了但未賦值。
- 物件屬性或陣列索引不存在。
- 函式沒有
return,或return後未寫值。
特性:
undefined是一個原始值(primitive),其類型為undefined。- 與
null、NaN不相等(===比較會回傳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/0、Math.sqrt(-1)等。
特性:
NaN的類型是number,但它 不等於自身(NaN === NaN為false)。- 必須使用
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 === NaN 為 false,容易造成判斷錯誤。 |
使用 Number.isNaN(value)(ES6)或 isNaN(value)(舊版)檢測。 |
自動型別轉換導致 undefined |
例如 obj.prop?.method(),如果 prop 為 undefined,整個表達式會回傳 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;
}
實際應用場景
API 回傳的空資料
- 後端可能回傳
null表示「查無結果」,而非undefined。前端收到後,應以=== null判斷並顯示「無資料」訊息。
- 後端可能回傳
表單驗證
- 使用者未填寫欄位時,表單資料物件的屬性可能是
undefined。驗證時可統一將undefined轉為null,簡化後續判斷。
- 使用者未填寫欄位時,表單資料物件的屬性可能是
數學運算與圖表繪製
- 資料點若產生
NaN,圖表函式庫(如 Chart.js)通常會跳過該點。開發者需要在資料清理階段使用Number.isNaN()过滤或替換為null,避免圖表斷裂。
- 資料點若產生
記憶體釋放與資源回收
- 當大型物件不再使用時,將變數設為
null,有助於垃圾回收器更快回收記憶體,提升效能。
- 當大型物件不再使用時,將變數設為
條件式的預設值
- 使用
??(Nullish Coalescing)運算子,僅在值為null或undefined時提供預設值,避免0、""、false被誤判為「空」。
- 使用
const limit = config.maxItems ?? 10; // 若 config.maxItems 為 null/undefined,使用 10
總結
**undefined**代表「尚未被賦值」或「不存在的屬性」,通常是系統自動產生。**null**則是開發者主動設定的「空」值,用來明確表示「此處應有資料,但目前沒有」。**NaN**表示「不是一個有效的數字」,在數學運算失敗時產生,且必須透過Number.isNaN()檢測。
掌握這三者的差異與正確的判斷方式,能讓你在撰寫 JavaScript 程式時,減少意外錯誤、提升除錯效率,同時寫出更具語意與可維護性的程式碼。未來在面對 API 整合、資料驗證或數值運算時,請依照上述最佳實踐來處理 null、undefined、NaN,讓你的程式更穩健、更易讀。祝你寫程式愉快!