本文 AI 產出,尚未審核

JavaScript ES6+ 新特性(Modern JS)

主題:Nullish Coalescing(??


簡介

在日常開發中,我們常常需要為變數提供「備援值」── 也就是當變數為 nullundefined 時,使用一個安全的預設值。過去 JavaScript 主要靠 邏輯或運算子||)來達成這件事,但 || 會把所有「假值」 (false, 0, '', NaN) 都視為「不存在」,這在許多情境下會導致意外的行為。

ECMAScript 2020 為了解決這個問題,正式加入了 Nullish Coalescing Operator(空值合併運算子)??。它只在左側運算元為 nullundefined 時才會返回右側的備援值,讓我們可以更精確地控制「何時使用預設值」。本文將深入介紹 ?? 的運作原理、實務範例、常見陷阱與最佳實踐,幫助你在程式碼中安全、簡潔地處理空值。


核心概念

1. 為什麼需要 ??

運算子 僅在左側為 null / undefined 時返回右側 會把所有「假值」都視為空值
??
` `
const a = 0;
const b = a || 10;   // b = 10  (0 被視為 falsy)
const c = a ?? 10;   // c = 0   (0 不是 null/undefined)

在需要保留 0、空字串 ''false 等合法值時,?? 是唯一正確的選擇。


2. 基本語法

let result = value ?? fallback;
  • value:可能是任意型別的表達式。
  • fallback:當 valuenullundefined 時使用的備援值。

注意?? 只能與 &&|| 結合使用,且必須加上括號以避免語法錯誤(a ?? b && ca ?? (b && c))。


3. 與解構賦值結合

function createUser({ name, age, role } = {}) {
  // 若外部傳入的物件缺少屬性,使用預設值
  const user = {
    name: name ?? '匿名',
    age: age ?? 18,
    role: role ?? 'guest',
  };
  return user;
}

解構賦值本身會在缺少屬性時給 undefined,配合 ?? 能一次解決「缺屬性」與「null」兩種情況。


4. 與函式參數的預設值比較

// 使用傳統預設值(只在參數為 undefined 時生效)
function greet(message = 'Hello') {
  console.log(message);
}
greet(undefined); // Hello
greet(null);      // null (預設值不會生效)

// 使用 ?? 取得相同效果,且同時處理 null
function greet2(message) {
  const msg = message ?? 'Hello';
  console.log(msg);
}
greet2(undefined); // Hello
greet2(null);      // Hello

?? 讓我們在函式內部自行決定何時使用備援值,彈性更高。


5. 多層 Nullish 合併

const config = {
  timeout: null,
  retry: undefined,
  endpoint: '',
};

const finalConfig = {
  timeout: config.timeout ?? 3000,   // 3000
  retry:   config.retry   ?? 5,      // 5
  endpoint: config.endpoint ?? '/api', // '' (空字串保留)
};

只要左側不是 null/undefined,即使是空字串也會直接使用,避免不必要的「預設覆寫」。


程式碼範例(實用範例 5 個)

範例 1:表單輸入的預設值

function getFormData(form) {
  return {
    username: form.username?.value ?? 'guest',
    age:      Number(form.age?.value) ?? 0,
    newsletter: form.newsletter?.checked ?? false,
  };
}
  • ?.(optional chaining)先保證不會因 form.usernamenull 而拋錯。
  • ?? 確保即使使用者留下空白,仍會得到合理的預設值。

範例 2:API 回傳資料的容錯處理

async function fetchUser(id) {
  const res = await fetch(`/api/users/${id}`);
  const data = await res.json();

  // API 可能回傳 null 或 undefined
  const name = data.name ?? '未知使用者';
  const email = data.email ?? '未提供';
  const avatar = data.avatarUrl ?? '/images/default-avatar.png';

  return { id, name, email, avatar };
}

使用 ?? 能在後端資料缺漏時自動補上前端需要的佔位資訊,提升使用者體驗。


範例 3:設定檔的層層覆寫

const defaultOptions = {
  theme: 'light',
  lang: 'zh-TW',
  debug: false,
};

function mergeOptions(userOptions) {
  return {
    theme: userOptions.theme ?? defaultOptions.theme,
    lang:  userOptions.lang  ?? defaultOptions.lang,
    debug: userOptions.debug ?? defaultOptions.debug,
  };
}

?? 僅在使用者真的沒有提供值時才採用預設,避免把 false0 等有效設定意外地改成預設。


範例 4:計算式中的安全除法

function safeDivide(a, b) {
  // 若除數為 null/undefined,視為 1;其他 falsy 值 (0) 仍保留
  const divisor = b ?? 1;
  return a / divisor;
}

console.log(safeDivide(10, 0));   // 0 (除以 0 仍會得到 Infinity,但不是預設值)
console.log(safeDivide(10, null)); // 10

此例展示 ?? 與傳統 || 的差異:b || 1 會把 0 當成 falsy 而改成 1,導致錯誤的計算結果。


範例 5:與 && 結合的條件渲染(React 範例)

function UserBadge({ user }) {
  return (
    <div className="badge">
      {/* 若 user 為 null/undefined,直接顯示「訪客」;若有值則顯示 name */}
      {user?.name ?? '訪客'}
    </div>
  );
}

在 JSX 中 ?? 常與 ?. 搭配,讓 UI 渲染邏輯既簡潔又安全。


常見陷阱與最佳實踐

陷阱 說明 解決方案
0、空字串 ''false 當作空值 使用 `
**與 &&、` ` 混用忘記加括號**
在左側產生副作用 func() ?? fallback 會執行 func(),即使結果不是 null,也會產生副作用。 確保左側表達式是「純」的或自行控制副作用。
錯把 null 視為合法值 某些 API 明確回傳 null 作為「沒有資料」的意義,此時應該保留 null 而不是覆寫。 若要保留 null,不要使用 ??,改用條件判斷或 `
使用在非空值的預設場景 有時候我們真的想把 0'' 視為「需要預設」的情況。 仍可使用 `

最佳實踐

  1. 只在需要區分 null/undefined 與其他 falsy 值時使用 ??
  2. 搭配 Optional Chaining (?.),先確保左側不會因屬性不存在拋錯。
  3. 保持運算子一致性:在同一行或同一段程式碼中,盡量避免同時使用 ??||&&,以免混淆。
  4. 加上註解說明:尤其在多人協作的專案,標註「為何使用 ?? 而非 ||」能減少未來的誤解。
  5. 測試所有可能的輸入:包括 nullundefined0''false,確保行為符合預期。

實際應用場景

  1. 設定檔與環境變數

    • 在 Node.js 中讀取 .env 時,常會看到 process.env.PORT ?? 3000,確保只在未定義時才使用預設埠號。
  2. 多語系文字的 fallback

    • 讀取 i18n JSON 時,messages[key] ?? messages['en-US'] 可在缺少翻譯時自動回退到英文。
  3. 第三方 API 的容錯

    • 某些 API 只在資料缺失時回傳 null,使用 ?? 能直接提供前端所需的占位圖或文字。
  4. React/Vue 中的條件渲染

    • user?.avatar ?? '/img/default.png' 讓 UI 不會因 usernull 而崩潰,同時保留空字串 '' 作為合法值。
  5. 函式庫的 API 設計

    • 公開函式接受選項物件時,內部使用 options.timeout ?? 5000,讓使用者能明確傳入 0(表示「立即」)而不被預設值覆寫。

總結

Nullish Coalescing Operator (??) 為 JavaScript 提供了一個精準且語意清晰的「空值備援」機制。相較於傳統的 ||,它只在左側為 nullundefined 時才會回傳右側值,讓 0''false 等合法的 falsy 值不會被意外覆寫。

透過本文的概念說明、實務範例與最佳實踐,你應該已經能在以下情境中自信使用 ??

  • 表單與 UI 的預設值
  • API 回傳資料的容錯處理
  • 設定檔與環境變數的合併
  • 函式參數與解構賦值的安全預設

只要記住「只在需要區分 null/undefined 與其他 falsy 值時使用 ??,並避免與 &&|| 混用而忘記加括號」,就能寫出更 可讀、可維護 的程式碼。未來在面對更複雜的資料流與多層物件結構時,?? 仍是你不可或缺的工具。祝你寫程式愉快,玩轉 Modern JS!