iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
佛心分享-IT 人職涯歷練

從 UI/UX 麻瓜到工程魔法師|從讀懂程式開始系列 第 11

Day 11|null、undefined、空字串、0 到底差在哪?前端為什麼一直在防空值?

  • 分享至 

  • xImage
  •  

開始接 API 之後,我很常看到這些判斷:

value ?? "-"
value || "-"
data?.customer?.name
if (value != null) {
  ...
}

以前我會覺得:

怎麼每個人都在防空值,而且寫法還不一樣?

後來才發現,問題就在於:

「沒有值」其實不只一種。


先看四個很常見的值

undefined
null
""
0

它們看起來都很像「沒東西」,但意思不一樣。

先簡單理解:

undefined
→ 還沒有被賦值 / 找不到這個值

null
→ 明確表示「目前沒有值」

""
→ 有一個 String,只是內容是空的

0
→ 有一個 Number,而且值就是 0

所以:

0

不是「沒有值」。

它是一個合法的數字。

同樣地:

""

也不是 undefined

它只是空字串。


undefined 是什麼?

例如:

let name;

console.log(name);

結果:

undefined

因為我們宣告了:

name

但還沒有給它內容。

也可能是讀取不存在的欄位:

const user = {
  name: "小潔",
};

console.log(user.age);

結果:

undefined

因為:

user 裡沒有 age

null 又是什麼?

null 通常是開發者或 API 明確放進去的:

const birthday = null;

可以理解成:

這個欄位存在,但目前沒有資料。

例如 API:

{
  "name": "小潔",
  "phone": null
}

這裡不是:

phone 不存在

而是:

phone 這個欄位存在
但是目前沒有值

所以 nullundefined 雖然都代表「沒有實際內容」,語意還是不太一樣。


空字串 "" 是真的有值

例如:

const name = "";

這裡:

typeof name

會是:

string

所以:

""

不是沒有資料型別。

它是一個真正的 String,只是長度是 0。

這在表單裡很常見。

例如使用者把 Input 清空後:

value = ""

有些 API 可能希望收到:

{
  "description": ""
}

但有些 API 卻希望:

{
  "description": null
}

甚至可能希望整個欄位不要送。

這三種意思可能完全不同。


0 更不能隨便當成空值

假設商品折扣:

const discount = 0;

0 代表:

折扣就是 0。

不是:

沒有折扣資料。

但如果寫:

const display = discount || "-";

結果會變成:

-

因為 JavaScript 會把:

0

視為 falsy。

這就是很容易踩的坑。


|| 到底在判斷什麼?

例如:

const value = 0;

console.log(value || "-");

結果:

-

因為 || 不是只判斷 nullundefined

它會把所有 falsy 值都當成前面不成立。

常見 falsy 值:

false
0
""
null
undefined
NaN

所以:

value || "-"

比較像:

如果 value 是 falsy,就使用 "-"


這就是為什麼有時候要用 ??

例如:

const value = 0;

console.log(value ?? "-");

結果是:

0

因為 ?? 只會處理:

null
undefined

流程可以理解成:

value 是 null 或 undefined 嗎?

是
→ 使用右邊

不是
→ 保留原本 value

所以:

0 ?? "-"

得到:

0

而:

"" ?? "-"

得到:

""

||?? 最重要的差別

可以直接看這張表:

| value | value || "-" | value ?? "-" |
| --- | --- | --- |
| undefined | "-" | "-" |
| null | "-" | "-" |
| "" | "-" | "" |
| 0 | "-" | 0 |
| false | "-" | false |

所以如果:

0
""
false

都是有意義的合法值,

通常:

??

會比:

||

更安全。


?. 又是在防什麼?

假設 API Response:

const user = {
  company: null,
};

直接寫:

user.company.name

會出錯。

因為:

company = null

後面不能繼續取:

.name

所以可以寫:

user.company?.name

意思是:

如果 company 不是 null / undefined,就繼續取 name。

如果:

company = null

結果會是:

undefined

而不是直接噴錯。


Optional Chaining 可以一路往下

例如:

data?.customer?.company?.name

可以理解成:

data 有嗎?
↓
有

customer 有嗎?
↓
有

company 有嗎?
↓
有

name

只要中間任何一層是:

null
undefined

就停止,回傳:

undefined

!= null 為什麼可以同時擋兩個?

這也是我以前很容易搞混的地方。

例如:

if (value != null) {
  ...
}

這裡故意使用:

!=

而不是:

!==

因為 JavaScript 裡:

null == undefined

結果是:

true

所以:

value != null

可以拿來判斷:

value 不是 null,也不是 undefined。

例如:

0 != null
// true
"" != null
// true
false != null
// true

但:

null != null
// false
undefined != null
// false

所以這種寫法其實很實用:

if (value != null) {
  // 這裡的 value 不會是 null 或 undefined
}

這和 if (value) 不一樣

例如:

const value = 0;

如果:

if (value) {
  ...
}

不會進去。

因為:

0

是 falsy。

但:

if (value != null) {
  ...
}

會進去。

因為:

0 不是 null
也不是 undefined

所以:

if (value)

問的是:

這個值 truthy 嗎?

而:

if (value != null)

問的是:

這個值是不是有存在,不是 null / undefined?

這兩件事不一樣。


放進 API 情境就更容易看懂

假設 API Response:

{
  "discount": 0,
  "description": "",
  "supplier": null
}

這三個欄位其實代表:

discount = 0
→ 有值,而且就是 0

description = ""
→ 有值,只是空字串

supplier = null
→ 明確沒有 supplier

如果全部都寫:

value || "-"

畫面可能全部顯示:

-

但這樣就把三種不同狀態混在一起了。

例如:

discount ?? "-"

會正確保留:

0

表單送 API 時更要小心

假設使用者清空一個欄位。

Frontend Form 得到:

description = "";

但 Backend API 的規格可能是:

null
→ 清除這個欄位

undefined
→ 不修改這個欄位

""
→ 儲存空字串

那這三個結果就完全不同。

例如 PATCH:

{
  description: undefined
}

某些 Request 序列化後可能根本不會送出這個欄位。

Backend 就可能理解成:

不修改 description。

但:

{
  description: null
}

如果 API 有支援,可能代表:

請把 description 清空。

所以 Debug PATCH 時,我現在會特別確認:

Form 現在是什麼值?
↓
Request Payload 實際送什麼?
↓
空字串?
null?
undefined?
還是根本沒有這個 key?

這往往不是小細節,而是直接影響資料到底會不會被更新。


我現在不會只問「它是不是空的」

以前:

這個值是空的嗎?

現在我會再多問一步:

它到底是哪一種空?

undefined?
null?
""?
0?
false?

因為它們在 JavaScript 裡:

型別不同
語意不同
判斷結果也不同

今天可以先記這組

?. 
→ 中間可能是 null / undefined
→ 安全往下取值


??
→ 只有 null / undefined 才使用預設值


||
→ falsy 都會使用預設值
→ 包含 0、""、false


value != null
→ 同時排除 null 和 undefined
→ 但保留 0、""、false

所以:

data?.discount ?? "-"

可以一步一步讀成:

data 有嗎?
↓
如果有,拿 discount

discount 是 null / undefined 嗎?
↓
是 → "-"

不是 → 保留原值

如果:

discount = 0

最後仍然會顯示:

0

這也是為什麼看起來只是幾個小符號,

到了真正的 API、表單和資料顯示裡,卻很容易直接造成 Bug。

下一篇可以接一個跟今天非常相關的實務問題:

為什麼明明把 Input 清空了,PATCH Request 卻沒有真的把資料清掉?undefinednull 和 Request Payload 到底發生了什麼?


上一篇
Day 10|一支 API 到底怎麼從前端一路跑到後端?
系列文
從 UI/UX 麻瓜到工程魔法師|從讀懂程式開始11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言