JavaScript Nullish Coalescing (空值合併運算子)
Nullish Coalescing(空值合併運算子)是 ES2020 引入的語法,使用 ?? 運算子。它用來在變數值為 null 或 undefined 時提供預設值。
基本語法
var result = value ?? defaultValue;
當 value 是 null 或 undefined 時,回傳 defaultValue;否則回傳 value。
var a = null ?? 'default';
console.log(a); // 'default'
var b = undefined ?? 'default';
console.log(b); // 'default'
var c = 'hello' ?? 'default';
console.log(c); // 'hello'
?? 與 || 的差異
傳統上我們會用 || 來提供預設值:
var name = userName || 'Guest';
但 || 會在左邊的值是任何 falsy 值時使用右邊的預設值。JavaScript 的 falsy 值包括:false、0、''(空字串)、null、undefined、NaN。
這可能導致非預期的結果:
// 使用 ||
var count = 0 || 10; // 10(0 是 falsy)
var text = '' || 'default'; // 'default'(空字串是 falsy)
var flag = false || true; // true(false 是 falsy)
// 使用 ??
var count = 0 ?? 10; // 0(0 不是 null/undefined)
var text = '' ?? 'default'; // ''(空字串不是 null/undefined)
var flag = false ?? true; // false(false 不是 null/undefined)
?? 只在值是 null 或 undefined 時才會使用預設值,其他 falsy 值(如 0、''、false)會被保留。實用範例
設定物件屬性預設值
function createUser(options) {
return {
name: options.name ?? 'Anonymous',
age: options.age ?? 0,
isAdmin: options.isAdmin ?? false,
bio: options.bio ?? ''
};
}
var user = createUser({ name: 'Mike' });
// { name: 'Mike', age: 0, isAdmin: false, bio: '' }
// 如果用 ||,age、isAdmin、bio 都會被覆蓋
function createUserWrong(options) {
return {
name: options.name || 'Anonymous',
age: options.age || 18, // 如果傳入 0,會變成 18
isAdmin: options.isAdmin || false,
bio: options.bio || 'No bio' // 如果傳入 '',會變成 'No bio'
};
}
處理函式參數
function greet(name, greeting) {
name = name ?? 'Guest';
greeting = greeting ?? 'Hello';
console.log(greeting + ', ' + name + '!');
}
greet(); // 'Hello, Guest!'
greet('Mike'); // 'Hello, Mike!'
greet('Mike', 'Hi'); // 'Hi, Mike!'
greet('Mike', ''); // ', Mike!'(空字串被保留)
存取可能不存在的資料
var user = {
settings: {
theme: null,
fontSize: 0,
showNotifications: false
}
};
// 使用 ?? 保留有效的 falsy 值
var theme = user.settings.theme ?? 'light'; // 'light'
var fontSize = user.settings.fontSize ?? 16; // 0(保留)
var showNotif = user.settings.showNotifications ?? true; // false(保留)
搭配 Optional Chaining
?? 經常和 Optional Chaining (?.) 一起使用:
var user = {
profile: {
name: 'Mike'
}
};
// 安全存取並提供預設值
var city = user?.profile?.address?.city ?? 'Unknown';
console.log(city); // 'Unknown'
var name = user?.profile?.name ?? 'Guest';
console.log(name); // 'Mike'
短路求值
?? 運算子也有短路求值的特性。如果左邊不是 null 或 undefined,右邊的運算式不會被執行:
var count = 0;
var value = 'hello' ?? count++; // count++ 不會執行
console.log(count); // 0
var value2 = null ?? count++; // count++ 會執行
console.log(count); // 1
不能直接與 && 或 || 混用
?? 不能直接和 && 或 || 混合使用,必須用括號明確指定優先順序:
// 錯誤:會拋出 SyntaxError
var result = a || b ?? c;
var result = a ?? b && c;
// 正確:使用括號
var result = (a || b) ?? c;
var result = a ?? (b && c);
這個限制是為了避免混淆,因為這三個運算子的行為不同。
Nullish Coalescing Assignment (??=)
ES2021 引入了 ??= 運算子,可以更簡潔地賦值:
var obj = { a: null, b: 'hello' };
// 只有當 a 是 null 或 undefined 時才賦值
obj.a ??= 'default';
console.log(obj.a); // 'default'
// b 不是 null/undefined,不會被改變
obj.b ??= 'new value';
console.log(obj.b); // 'hello'
// 等同於
obj.a = obj.a ?? 'default';
實際應用場景
設定 API 參數
async function fetchUsers(options) {
var page = options?.page ?? 1;
var limit = options?.limit ?? 10;
var sortBy = options?.sortBy ?? 'createdAt';
var url = '/api/users?page=' + page + '&limit=' + limit + '&sort=' + sortBy;
return fetch(url);
}
// 使用預設值
fetchUsers({}); // page=1, limit=10
fetchUsers({ page: 2 }); // page=2, limit=10
fetchUsers({ limit: 0 }); // limit=0(0 被保留)
表單處理
function processForm(formData) {
return {
email: formData.email ?? '',
age: formData.age ?? null,
subscribed: formData.subscribed ?? false,
// 空字串和 0 會被保留,只有 null/undefined 才使用預設值
};
}
瀏覽器支援
Nullish Coalescing 是 ES2020 的功能,現代瀏覽器都已支援:
| 瀏覽器 | 支援版本 |
|---|---|
| Chrome | 80+ |
| Firefox | 72+ |
| Safari | 13.1+ |
| Edge | 80+ |
| Node.js | 14+ |
總結
| 運算子 | 使用預設值的條件 |
|---|---|
|| | 左邊是 falsy 值(false、0、''、null、undefined、NaN) |
?? | 左邊是 null 或 undefined |
選擇建議:
- 如果
0、''、false是有效值,應使用?? - 如果想把所有 falsy 值都視為「沒有值」,使用
||