JavaScript中雙問號(hào)(??)操作符詳解
在 JavaScript 中,?? 被稱為空值合并操作符(Nullish Coalescing Operator)。這是 ES2020(ES11)引入的一項(xiàng)新特性,主要用于處理默認(rèn)值的賦值問題。相比傳統(tǒng)的 || 邏輯或操作符,?? 在判斷標(biāo)準(zhǔn)上更加嚴(yán)格,能更準(zhǔn)確地表達(dá)“僅在值為 null 或 undefined 時(shí)使用默認(rèn)值”的意圖。本文將詳細(xì)介紹 ?? 的作用、用法、與其他操作符的區(qū)別及實(shí)際應(yīng)用場(chǎng)景。
一、雙問號(hào)(??)操作符概述
1. 什么是空值合并操作符
空值合并操作符 ?? 是一種邏輯運(yùn)算符,用于在左側(cè)表達(dá)式的值為 null 或 undefined 時(shí),返回右側(cè)的默認(rèn)值。簡單來說,就是:
- 如果左側(cè)的值是
null或undefined,返回右側(cè)的值; - 否則,返回左側(cè)的值。
2. 基本語法
let result = a ?? b;
a是要檢查的值;b是當(dāng)a為null或undefined時(shí)使用的默認(rèn)值;- 最終
result的值是a或b,取決于a是否為null或undefined。
3. 簡單示例
let username; let displayName = username ?? "匿名用戶"; console.log(displayName); // 輸出:"匿名用戶"
在這個(gè)例子中,因?yàn)?username 是 undefined,所以最終 displayName 賦值為右側(cè)的 “匿名用戶”。
如果 username 有一個(gè)實(shí)際的值,比如:
let username = "張三"; let displayName = username ?? "匿名用戶"; console.log(displayName); // 輸出:"張三"
那么就直接使用 username 的值,不使用默認(rèn)值。
二、為什么需要 ?? 操作符
1. 傳統(tǒng)的 || 存在的問題
在 ?? 出現(xiàn)之前,我們常常用邏輯或 || 來處理默認(rèn)值,比如:
let username = ""; let displayName = username || "匿名用戶"; console.log(displayName); // 輸出:"匿名用戶"
問題是,|| 會(huì)把**所有假值(falsy value)**都當(dāng)成無效,包括:
false0NaN""(空字符串)nullundefined
上面例子中,雖然 username 是空字符串 "",理論上是有意義的(可能用戶就是想提交一個(gè)空的名字),但 || 認(rèn)為空字符串是無效的,于是強(qiáng)行用了默認(rèn)值。這并不是我們想要的。
2. ?? 更合理的默認(rèn)值邏輯
?? 只在 null 和 undefined 時(shí)才使用默認(rèn)值,其它的假值(比如 0、false、"")都會(huì)被當(dāng)作有效值保留下來。
修改上面的例子:
let username = ""; let displayName = username ?? "匿名用戶"; console.log(displayName); // 輸出:""
這次不會(huì)強(qiáng)行替換默認(rèn)值,而是保留了空字符串。這就更加符合實(shí)際開發(fā)中對(duì)于“值是否存在”的真實(shí)判斷需求。
三、?? 操作符的使用細(xì)節(jié)
1. null 和 undefined 的區(qū)別對(duì)待
?? 只關(guān)心 null 和 undefined,忽略其他 falsy 值。
示例:
console.log(false ?? "默認(rèn)值"); // false
console.log(0 ?? 100); // 0
console.log("" ?? "默認(rèn)字符串"); // ""
console.log(null ?? "默認(rèn)值"); // "默認(rèn)值"
console.log(undefined ?? "默認(rèn)值"); // "默認(rèn)值"
可以看到,只有當(dāng)值為 null 或 undefined 時(shí),右側(cè)的默認(rèn)值才生效。
2. 與三元表達(dá)式(條件表達(dá)式)的對(duì)比
很多人可能習(xí)慣使用三元表達(dá)式:
let result = (a !== null && a !== undefined) ? a : b;
其實(shí)用 ?? 可以大大簡化:
let result = a ?? b;
這樣代碼更加簡潔,易讀性也更好。
3. 與邏輯運(yùn)算符優(yōu)先級(jí)相關(guān)
?? 的優(yōu)先級(jí)比 || 和 && 要低,但比賦值 = 高。在組合使用時(shí),需要注意加括號(hào)明確邏輯。
錯(cuò)誤示例:
let a = null || undefined ?? "默認(rèn)值"; // SyntaxError: Unexpected token '??'
正確寫法應(yīng)該加括號(hào):
let a = (null || undefined) ?? "默認(rèn)值"; console.log(a); // 輸出:"默認(rèn)值"
或者徹底拆開來寫,避免混用。
4. 禁止與 && 和 || 直接混用
JavaScript 規(guī)定,如果要同時(shí)使用 ?? 和 &&、||,必須用括號(hào)包裹清晰邏輯,否則會(huì)拋出 SyntaxError。
例如:
let x = (a || b) ?? c;
而不是:
let x = a || b ?? c; // ? 錯(cuò)誤,語法錯(cuò)誤
四、實(shí)際應(yīng)用場(chǎng)景
1. 設(shè)置默認(rèn)參數(shù)
函數(shù)參數(shù)如果沒有傳值,可以用 ?? 設(shè)置默認(rèn)值。
function greet(name) {
let userName = name ?? "游客";
console.log(`你好,${userName}`);
}
greet("李雷"); // 你好,李雷
greet(); // 你好,游客
2. 讀取對(duì)象屬性
讀取對(duì)象中的某個(gè)屬性時(shí),防止屬性不存在導(dǎo)致顯示錯(cuò)誤。
let user = {
name: "小明",
age: 0
};
console.log(user.name ?? "匿名"); // 小明
console.log(user.age ?? "未知"); // 0
console.log(user.gender ?? "保密"); // 保密
這里即使 age 是 0,?? 也不會(huì)替換成默認(rèn)值。
3. 配合解構(gòu)賦值使用
在解構(gòu)賦值時(shí),結(jié)合 ?? 可以更加靈活處理默認(rèn)值。
let settings = {
theme: null,
layout: "grid"
};
let theme = settings.theme ?? "light";
let layout = settings.layout ?? "list";
console.log(theme); // light
console.log(layout); // grid
如果 theme 是 null,則使用默認(rèn)值 light;如果 layout 已經(jīng)有值 grid,則保留。
4. 配合可選鏈(?.)使用
?? 和可選鏈(?.)搭配使用非常高效,可以避免層層判斷。
let user = {
profile: {
nickname: ""
}
};
let nickname = user.profile?.nickname ?? "未命名";
console.log(nickname); // ""
這里即使 nickname 是空字符串,也不會(huì)被替換;如果 profile 不存在,也不會(huì)拋出異常,而是走默認(rèn)值。
五、常見問題與注意事項(xiàng)
1. 區(qū)分 falsy 值和 null/undefined
?? 只針對(duì) null 和 undefined,不像 || 那樣針對(duì)所有 falsy 值。這是它最核心的區(qū)別。務(wù)必根據(jù)業(yè)務(wù)場(chǎng)景選擇使用哪種操作符。
如果你希望 0、false、“” 也能觸發(fā)默認(rèn)值,用 ||; 如果你只關(guān)心 null 或 undefined,應(yīng)該用 ??。
2. 語法錯(cuò)誤要注意加括號(hào)
混合使用 &&、|| 和 ?? 時(shí),務(wù)必加括號(hào)明確優(yōu)先級(jí),否則 JavaScript 會(huì)拋出語法錯(cuò)誤。
3. 瀏覽器兼容性
??是 ES2020 新增的特性;- 現(xiàn)代瀏覽器(Chrome 80+,F(xiàn)irefox 72+,Edge 80+,Safari 13.1+)基本已經(jīng)支持;
- 如果需要兼容老舊瀏覽器(比如 IE11),可以使用 Babel 轉(zhuǎn)譯處理。
六、總結(jié)
空值合并操作符 ?? 是一個(gè)非常實(shí)用的 JavaScript 新特性,它可以幫助我們更加準(zhǔn)確地處理默認(rèn)值,避免傳統(tǒng) || 在 0、false、“” 等值上的邏輯誤判。掌握 ?? 的使用,不僅可以讓你的代碼更加簡潔,也能讓邏輯更加清晰明確。特別是在函數(shù)參數(shù)處理、對(duì)象屬性讀取、配置項(xiàng)設(shè)置等場(chǎng)景中,?? 都能發(fā)揮極大的作用。
在日常開發(fā)中,只要牢記:只有在值為 null 或 undefined 時(shí),才使用默認(rèn)值,你就能準(zhǔn)確地應(yīng)用好 ??,寫出更優(yōu)雅、更健壯的 JavaScript 代碼。
到此這篇關(guān)于JavaScript中雙問號(hào)(??)操作符詳解的文章就介紹到這了,更多相關(guān)JavaScript 雙問號(hào)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
p5.js 畢達(dá)哥拉斯樹的實(shí)現(xiàn)代碼
這篇文章主要介紹了p5.js 畢達(dá)哥拉斯樹的實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03
JavaScript實(shí)現(xiàn)時(shí)間表動(dòng)態(tài)效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)時(shí)間表動(dòng)態(tài)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
html向js方法傳遞參數(shù)具體實(shí)現(xiàn)
html如何向js方法傳遞參數(shù),在本文將為大家詳細(xì)介紹下html注冊(cè)事件向引用方法中的傳參問題,感興趣的朋友可以參考下,希望對(duì)大家有所幫助2013-08-08
JavaScript判斷數(shù)組的方法總結(jié)與推薦
這篇文章主要給大家介紹了關(guān)于JavaScript判斷數(shù)組方法的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-02-02
小程序云開發(fā)獲取不到數(shù)據(jù)庫記錄的解決方法
這篇文章主要為大家詳細(xì)介紹了小程序云開發(fā)獲取不到數(shù)據(jù)庫記錄的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05
深入理解 webpack 文件打包機(jī)制(小結(jié))
這篇文章主要介紹了深入理解 webpack 文件打包機(jī)制(小結(jié)),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01
深入探討JavaScript異步編程中Promise的關(guān)鍵要點(diǎn)
這篇文章將全面深入地探討Promise,包括其前身、歷史、能力、優(yōu)點(diǎn)、缺點(diǎn)以及提供每個(gè)方法的案例,感興趣的小伙伴可以跟隨小編一學(xué)習(xí)一下2023-06-06
JS中for,for...in,for...of和forEach的區(qū)別和用法實(shí)例
JS遍歷數(shù)組(循環(huán)數(shù)組)的方式有多種,可以使用傳統(tǒng)的for循環(huán),也可以使用升級(jí)版的for in循環(huán),還可以使用Array類型的forEach() 方法,這篇文章主要給大家介紹了關(guān)于JS中for、for...in、for...of和forEach的區(qū)別和用法的相關(guān)資料,需要的朋友可以參考下2021-11-11
js實(shí)現(xiàn)select跳轉(zhuǎn)菜單新窗口效果代碼分享
這篇文章主要介紹了js實(shí)現(xiàn)select跳轉(zhuǎn)菜單新窗口效果代碼分享,實(shí)現(xiàn)很簡單,推薦給大家,有需要的小伙伴可以參考下2015-08-08

