本文 AI 產出,尚未審核

JavaScript ES6+ 新特性:Optional Chaining(?.)

簡介

在日常開發中,我們常常需要從深層的物件結構中取得資料,例如 user.profile.address.city。如果其中任意一層為 nullundefined,傳統的寫法會拋出 TypeError,導致程式碼必須寫滿大量的防呆檢查 (if (obj && obj.prop && ...))。
ES2020(亦稱 ES11)引入的 Optional Chaining(可選鏈)?.,讓這類防呆檢查變得簡潔且可讀。只要在屬性存取、函式呼叫或陣列存取前加上 ?.,若左側為 nullundefined,整個運算會直接回傳 undefined,不會拋錯。

對於 初學者,Optional Chaining 能降低因忘記檢查而產生的錯誤;對 中級開發者,則提供更乾淨的程式碼風格,提升維護性與可讀性。因此,掌握這個語法是使用 Modern JS 的必備功力。


核心概念

1. 基本語法

obj?.propobj?.[expr]func?.(...args)arr?.[index] 為四種常見形式。當左側的 參照值nullundefined 時,結果直接是 undefined;否則會正常求值。

const user = {
  name: "Alice",
  profile: {
    address: {
      city: "Taipei"
    }
  }
};

console.log(user?.profile?.address?.city); // "Taipei"
console.log(user?.profile?.phone?.number); // undefined (不會拋錯)

重點?. 只會檢查 左側 是否為 null/undefined,不會對其他 falsy 值(如 0''false)做特別處理。


2. 可選函式呼叫

const api = {
  getUser: (id) => ({ id, name: "Bob" })
};

const result1 = api.getUser?.(123); // 正常呼叫,回傳物件
const result2 = api.fetchUser?.(123); // fetchUser 不存在,回傳 undefined

若函式本身不存在,使用 ?.() 能安全地「不呼叫」而不會產生 TypeError


3. 可選陣列存取

const matrix = [
  [1, 2],
  [3, 4]
];

console.log(matrix?.[0]?.[1]); // 2
console.log(matrix?.[2]?.[0]); // undefined (matrix[2] 為 undefined)

?.[expr] 讓我們可以在動態索引或多層陣列時,同樣享有防呆保護。


4. 與 Nullish Coalescing (??) 結合

Optional Chaining 常與 Nullish Coalescing 搭配使用,提供「若結果為 undefined/ null 則使用預設值」的語意。

const config = {
  timeout: 0,
  retry: null
};

const timeout = config?.timeout ?? 5000; // 0 為有效值,結果 0
const retry   = config?.retry   ?? 3;    // null 被視為 nullish,結果 3

5. 只在 左值 使用 ?.,不可在 右值

// 錯誤寫法:會 SyntaxError
// const value = (obj?.prop) ? true : false;

// 正確寫法
const value = obj?.prop ? true : false;

?. 必須緊貼在 屬性、方法或索引 前方,不能放在運算子或條件式的其他位置。


程式碼範例(實用示例)

範例 1:安全取得 API 回傳的深層資料

// 假設從遠端取得的資料結構不一定完整
function fetchUserInfo(id) {
  // 模擬回傳值
  return {
    id,
    profile: {
      // address 可能不存在
      // address: { city: "Kaohsiung" }
    }
  };
}

const data = fetchUserInfo(42);

// 使用 Optional Chaining 直接取得城市名稱,若不存在則回傳 '未知'
const city = data?.profile?.address?.city ?? "未知";
console.log(city); // "未知"

範例 2:在 React 組件中防止渲染錯誤

function UserCard({ user }) {
  return (
    <div className="card">
      {/* 若 user.avatar 為 undefined,img src 會是 undefined,不會拋錯 */}
      <img src={user?.avatar?.url} alt={user?.name ?? "匿名"} />
      <h3>{user?.name ?? "未命名使用者"}</h3>
      <p>{user?.profile?.bio ?? "沒有簡介"}</p>
    </div>
  );
}

範例 3:可選函式呼叫搭配事件處理

function onClick(event) {
  // 若外部傳入的 callback 為 undefined,直接略過呼叫
  const callback = event?.target?.onCustomClick;
  callback?.(event); // 安全呼叫
}

範例 4:多層陣列資料的安全存取

const scores = [
  [10, 20],
  [30, 40, 50]
];

function getScore(row, col) {
  // 若 row、col 超出範圍,回傳 -1 而不是拋錯
  return scores?.[row]?.[col] ?? -1;
}

console.log(getScore(1, 2)); // 50
console.log(getScore(2, 0)); // -1

範例 5:結合解構賦值的防呆寫法

const response = {
  data: {
    user: {
      name: "Carol"
    }
  }
};

// 使用可選鏈結取得 name,若不存在則給預設值
const { name = "匿名" } = response?.data?.user ?? {};
console.log(name); // "Carol"

常見陷阱與最佳實踐

陷阱 說明 建議的做法
誤用在左值 obj?.prop = value 會產生 SyntaxError,因為 ?. 只能用於讀取。 若需要條件賦值,先檢查再賦值:if (obj) obj.prop = value;
&& 混用 仍習慣寫 obj && obj.prop?.sub,會造成冗餘且降低可讀性。 完全使用 ?.obj?.prop?.sub
忽略 nullundefined 之差 ?. 僅檢查 null/undefined,若左側為 0''false,仍會正常求值。 依需求搭配 ?? 或顯式檢查 falsy 值。
過度使用 把所有屬性都包成 ?.,會隱藏資料結構錯誤,難以偵錯。 只在不確定的外部來源(API、使用者輸入)使用;內部已知結構則保留直接存取以利錯誤捕捉。
與 Proxy、Proxy Revocation ?. 在 Proxy 物件上仍會觸發 get 捕獲器,可能產生副作用。 瞭解 Proxy 行為,必要時在 Proxy 內自行處理 undefined

最佳實踐

  1. 明確搭配預設值:使用 ?? 或三元運算子提供 fallback,避免傳遞 undefined 到後續流程。
  2. 保持可讀性:在同一行中不要混用太多 ?.,適度斷行或使用中間變數提升可讀性。
  3. 工具支援:ESLint 的 no-unsafe-optional-chainingprefer-optional-chain 規則能協助統一寫法。
  4. 測試覆蓋:對外部 API 的回傳加入單元測試,確保在缺少欄位時仍能得到預期結果。

實際應用場景

  1. 前端 UI 渲染
    • 從後端取得的 JSON 可能缺少某些欄位,使用 ?. 防止畫面崩潰。
  2. Node.js 後端服務
    • 處理多層設定檔 (config.env?.db?.host) 時,避免因缺少環境變數拋錯。
  3. 第三方 SDK 整合
    • 某些 SDK 方法在特定版本才提供,使用 sdk?.method?.() 保證向下相容。
  4. React Hook 中的依賴
    • useEffect(() => { fetchData?.(); }, [fetchData]);,當 fetchDataundefined 時不會觸發錯誤。
  5. 資料驗證與轉換
    • 在表單資料轉換為模型前,使用 form?.field?.value ?? '' 取代繁瑣的 if 判斷。

總結

Optional Chaining (?.) 為 ES2020 引入的強大語法糖,讓深層物件存取變得安全且簡潔。它解決了傳統防呆寫法冗長、易錯的痛點,特別適合處理外部資料、API 回傳、動態屬性存取等情境。
掌握正確的使用方式、避免常見陷阱,並結合 Nullish CoalescingESLint 等工具,就能在日常開發中寫出更乾淨、可維護的程式碼。未來隨著 JavaScript 生態持續演進,Optional Chaining 也將成為撰寫 Modern JS 時的基本功,值得每位開發者深入了解與運用。祝你在程式之路上,因為「可選」而更從容!