JSON 工具箱

空值用 null 還是省略欄位

結論:`null` 表示「這個欄位存在,但沒有值」,省略表示「這個欄位不存在」。PATCH 介面、設定合併、前端表單回填三處最容易因此出錯,判斷標準是「消費方需不需要知道這個欄位被顯式清空」。

進階約 3 分鐘發佈於 2026-10-30更新於 2026-10-30
null 與欄位省略的語意差異

結論:null 表示欄位存在但值為空,省略表示欄位不存在,選錯會直接改變業務含義;PATCH 請求必須用 null 表示清空、省略表示不修改,回傳體與設定合併則各自統一約定。

語意差異

{ "nickname": null }

欄位存在,值是空。消費方知道「這個欄位被顯式清空過」。

{ }

欄位不存在。消費方無法判斷是「沒設定」還是「不支援」。

在 JavaScript 裡這個差異非常具體:

'nickname' in obj          // false —— 欄位不存在
obj.nickname === null      // true  —— 欄位存在且為 null
obj.nickname === undefined // true  —— 兩種情況都成立

三處必須區分的地方

一、PATCH 請求。

PATCH /users/1
{ "nickname": null }

含義是「把暱稱清空」。

PATCH /users/1
{ }

含義是「什麼都不改」。如果 PATCH 實作裡把「值為 null」和「欄位缺失」當成一回事,使用者就永遠沒法清空暱稱——只能改成空字串,而空字串和 null 在業務上往往是兩回事。

正確實作要用「欄位是否存在」判斷,而不是「值是否為 null」:

if (Object.hasOwn(patch, 'nickname')) {
  target.nickname = patch.nickname;   // 允許寫成 null
}

二、設定合併。 省略表示「繼承預設」,null 表示「顯式停用」。這層語意在 Helm、Kubernetes 的 values 合併裡非常常見。

三、前端表單回填。 輸入框拿到 null 應該顯示為空,拿到 undefined(欄位不存在)通常也顯示為空,但提交時要區分:原本有值、現在清空 → 提交 null;從未填過 → 不提交這個欄位。不區分會導致「清空操作被當成未修改」。

常規建議

場景 建議
查詢介面的回傳體 保留 null,保持結構穩定,前端型別好寫
PATCH 請求體 嚴格區分:null 清空,省略不改
PUT 全量替換 可以省略,但語意是「整份覆蓋」,缺失欄位視為刪除
設定合併 省略 = 用預設值,null = 顯式關閉
資料庫儲存 null 表示未知/不適用;空字串表示「已知為空」

回傳體盡量保持結構穩定是重要的一條。列表介面裡有些物件帶 avatar、有些不帶,前端每次都要 'avatar' in item 判斷,很容易出錯。統一回 avatar: null 更好寫。

別做的三件事

別用空字串代替 null。 "" 和 null 在業務上經常不同:暱稱為空串是「使用者設定了空暱稱」,null 是「沒設定」。

別用 0 或 -1 表示「沒有值」。 數值欄位裡 0 是合法值,當哨兵值用會讓統計邏輯出錯。

別在同一個欄位上混用兩種約定。 有的介面回 null,有的省略欄位,前端就得寫兩套判斷。約定一次,寫進文件。

常見問題

什麼時候必須用 null 而不是省略欄位?

消費方需要區分「欄位被顯式清空」和「欄位從未修改」時必須用 null。典型場景是 PATCH 請求:傳 null 表示清空該欄位,不傳表示保持原值。

PATCH 介面如何區分「清空」和「不修改」?

用「欄位是否存在」判斷,而不是「值是否為 null」。例如用 Object.hasOwn(patch, 'nickname') 判斷後再賦值,這樣 null 才能作為合法值生效。

為什麼回傳體應該盡量保留 null?

保留 null 能讓回傳結構穩定,前端不必對每個可選欄位寫 'avatar' in item 判斷。列表介面裡有些物件帶某欄位、有些不帶,會顯著增加消費方出錯的機率。

延伸閱讀