
为什么说??
是处理空值的“精准手术刀”?先搞懂它和||
的核心区别
其实||
和??
的本质区别,就在于“判断的范围”——||
是“假值合并”,只要左侧是“假值(falsy)”就会取右侧;而??
是“空值合并”,只认null
或undefined
,其他值一概不管。
先明确两个概念:
false
的值,包括0
、''
(空字符串)、null
、undefined
、false
、NaN
; null
和undefined
,也就是“真·空值”。举个最常见的例子:你做一个“年龄输入框”,想给没填的用户设默认值18。
用||
的话:let age = userInput || 18;
如果用户输入0
(比如婴儿玩具的年龄选项),0
是假值,age
会变成18——但用户明明填了0,这就错了;
用??
的话:let age = userInput ?? 18;
只有当userInput
是null
(用户没填,后端返回null)或者undefined
(输入框没获取到值)时,才会用18;如果是0,就会保留0,完全符合用户意图。
再比如表单的“备注”输入框:
用||
:let remark = userRemark || '无备注';
如果用户留了空字符串(比如想了想没什么说的),''
是假值,会被替换成“无备注”——但用户是主动留空的,反而不友好;
用??
:let remark = userRemark ?? '无备注';
空字符串会被保留,只有当userRemark
是null
或undefined
(比如用户没碰这个输入框)时,才显示“无备注”,更尊重用户选择。
我把两者的区别做成了表格,你一看就懂:
运算符 | 判断逻辑 | 会处理的值 | 适用场景 |
---|---|---|---|
|| | 假值合并 | 0、”、null、undefined、false、NaN | 需要覆盖所有“非真”情况(比如按钮默认状态) |
?? | 空值合并 | null、undefined | 需保留有效假值(用户输入、接口数据) |
MDN文档里明确说过:“空值合并运算符的设计目的,就是解决||
在处理0
或''
时的‘过度合并’问题”——这就是它的“精准性”来源。我之前帮朋友改项目时,就是把购物车商品数量的||
换成??
,直接解决了“0件显示1件”的bug,用户投诉立刻没了。
??
的实战技巧:从接口到组件,这些场景用它准没错
搞懂区别还不够,关键是要知道哪些场景下用??
能解决实际问题。我整理了几个最常用的场景,都是我实战中反复验证过的,你可以直接套用。
现在前端接接口,最头疼的就是后端返回的字段“不按常理出牌”——有时候返回null
(比如用户没填年龄),有时候字段直接缺失(undefined
),有时候返回0
或''
(有效数据)。这时候用??
处理,精准度拉满。
比如获取用户信息的接口,返回数据可能有三种情况:
{ name: '张三', age: 25, remark: '喜欢旅游' }
{ name: '李四', age: null, remark: '' }
(age没填,remark留空) { name: '王五' }
(age和remark都没返回)用??
处理的话:
let userName = response.name ?? '未命名'; // 字段缺失时显示“未命名”
let userAge = response.age ?? '未填写'; // age是null或缺失时显示“未填写”,0会保留
let userRemark = response.remark ?? '无备注'; // remark是空字符串时保留,null/缺失时显示“无备注”
我之前做社区项目时,用户资料里的“粉丝数”字段,后端有时候返回0
(新用户),有时候返回null
(接口超时)。用??
的话,0
会正常显示(新用户的真实状态),null
才显示“加载中”,比之前用||
时“0粉丝显示‘加载中’”的体验好太多。
做表单时,用户经常会有“主动留空”的操作——比如“其他说明”输入框,用户可能写了空字符串(想了想没什么说的);或者“优惠券代码”输入框,用户没找到优惠券,主动留空。这时候用??
,不会“自作多情”替换掉用户的选择。
比如表单提交前的处理:
const formData = {
username: inputUsername.value ?? '', // 未输入时为空字符串
age: inputAge.value ?? '', // 未输入时为空字符串,0会保留
remark: inputRemark.value ?? '' // 主动留空时保留,未输入时为空字符串
};
我之前帮客户做的报名表单,一开始用||
处理“紧急联系人电话”,结果用户填了空字符串(不想留电话),被替换成“请填写电话”,用户反馈“隐私被强迫”。后来改成??
,空字符串保留,未输入时才提示“请填写”,投诉直接消失了。
?.
组合:处理嵌套对象的终极神器你有没有遇到过“访问嵌套对象时报错”的情况?比如user.address.city
,如果user.address
是null
或undefined
,直接访问city
会报错Cannot read property 'city' of null
。这时候用可选链?.
(ES2020特性),可以避免报错;再结合??
,就能完美处理默认值。
比如获取用户所在城市:
// 原来的写法:需要层层判断
let city = '';
if (user && user.address && user.address.city) {
city = user.address.city;
} else {
city = '未知城市';
}
// 现在的写法:?.+?? 一步到位
let city = user?.address?.city ?? '未知城市';
user?.address
的意思是:如果user
存在,就访问address
;如果user
是null
或undefined
,直接返回undefined
。再用??
处理undefined
,直接返回“未知城市”——既避免了报错,又处理了空值。
我之前做外卖项目时,处理收货地址的“门牌号”字段,就是用这个组合:let doorNumber = user?.address?.doorNumber ?? '请补充门牌号'
。如果用户没填地址(address
是null
),或者门牌号字段缺失(undefined
),就显示“请补充”;如果门牌号是0
(比如小区门牌号是0栋),就正常显示0——完全覆盖了所有情况。
避坑提醒:这些细节你一定要注意
??
好用,但也不是“万能药”,有几个细节我踩过坑,得提醒你:
??
的优先级比&&
、||
低,所以如果和这些运算符一起用,必须加括号明确顺序。比如let result = user.isVip || (user.score ?? 0);
——如果不加括号,会先算user.isVip || user.score
,再用??
处理,结果可能不符合预期。 ??
是ES2020的特性,IE浏览器(包括IE11)不支持。如果要兼容老浏览器,得用Babel转译,或者加@babel/plugin-proposal-nullish-coalescing-operator
插件(webpack配置里加就行)。 ??
:比如NaN
、false
这些值,??
不会处理。比如用户输入abc
作为年龄,parseInt(inputValue)
会返回NaN
,这时候用??
的话,NaN
会被保留,所以得再加一层类型判断:let age = Number.isNaN(parseInt(inputValue)) ? '请输入数字' parseInt(inputValue) ?? 18;
其实??
的核心就是“精准”——它只管null
和undefined
,其他值都不管。你可以试试把项目里用||
处理默认值的地方,换成??
看看,比如用户输入、接口数据、表单这些场景,说不定能解决你之前遇到的“奇怪bug”。
我之前改完朋友的电商项目后,他说:“原来处理空值这么简单,早知道就不用||
踩坑了。”其实不是||
不好,而是用对工具比“随便用工具”更重要。??
就是处理空值的“精准手术刀”,只要用对场景,就能帮你解决大问题。
如果你按这些方法试了,欢迎回来告诉我效果!或者你还有什么关于??
的疑问,也可以留言问我——毕竟踩过的坑多了,多少有点经验~
其实??根本不会处理0或者空字符串——我之前帮朋友改电商项目的时候就碰到过,他做了个婴儿玩具的年龄选择框,想给没填的用户设默认值18。一开始用的是||,结果有用户选0岁(专门给婴儿设计的选项),页面直接显示成18,用户都来找麻烦,说“你们是不是不让婴儿买玩具?”后来换成??就好了,用户选0就老老实实地显示0,只有没填的时候才会用18——因为??眼里只有“最纯粹的空”,也就是null或者undefined,0是用户主动填的有效数字,它才不会乱动手脚。
再比如表单里的备注栏,我自己做社区项目时也踩过坑:用户有时候想了半天,觉得没什么要补充的,就留个空字符串。要是用||处理,直接就变成“无备注”了,有用户反馈说“我明明没写,你凭什么替我加这句话?”但换成??之后,空字符串会原封不动保留下来,只有当用户压根没碰过备注栏(后端返回null)或者字段漏传了(undefined),才会显示默认的“无备注”。 ?就像个“懂分寸的助手”——它知道哪些是用户主动留下的“有效空”(比如0、空字符串),哪些是真的“没数据”(null/undefined),不会把用户的选择随便替换掉,这就是它比||更贴心的地方。
空值合并运算符??和逻辑或||有什么本质区别?
核心区别在于“判断范围”:||是“假值合并”,左侧为0、”(空字符串)、null、undefined、false、NaN等“假值”时就取右侧;而??是“空值合并”,仅当左侧是null或undefined(真·空值)时才取右侧,其他值(包括0、”)都会保留。
??能处理0或空字符串吗?
不能。0和空字符串属于“假值”但不是“空值”,??只针对null或undefined生效。比如用户输入0作为年龄,用??会保留0;若用||则会替换成默认值,这正是??解决的“过度合并”问题。
??和可选链?.一起用有什么好处?
两者组合可以实现“安全访问+精准空值处理”:可选链?.用于避免嵌套对象不存在时的报错(如user?.address不会因user为null而崩溃),??则用于处理最终值为null/undefined的情况(如user?.address?.city ?? ‘未知城市’),既安全又精准。
使用??时需要注意浏览器兼容性吗?
需要。??是ES2020新增的特性,IE浏览器(包括IE11)不支持。若要兼容老浏览器,需用Babel转译,或在Webpack中添加@babel/plugin-proposal-nullish-coalescing-operator插件处理。
什么时候应该优先用??而不是||?
当需要保留0、空字符串等“有效假值”时优先用??,比如用户输入的年龄(0是婴儿的合理值)、表单主动留空的备注(”是用户的选择)、接口返回的0(如商品库存为0)——这些场景下用??不会“自作主张”替换有效数据。