空值合并运算符??对null和undefined一视同仁,仅当左侧为二者之一时返回右侧默认值;其余所有值(如0、false、''、nan)均原样返回,不触发替换。

空值合并运算符 ?? 对 undefined 和 null 一视同仁——两者都会触发右侧默认值的返回,但它们在语义和实际使用中仍有本质区别。理解这点,关键不在 ?? 怎么处理它们,而在于你为什么传入其中一个而不是另一个。
?? 不区分语义,只识别“空值性”
?? 的判定逻辑非常机械:只要左侧是 null 或 undefined,就短路并取右侧值;其余所有值(包括 0、false、''、NaN)都原样返回。它不关心这个 null 是主动清空的,也不管那个 undefined 是属性缺失还是参数没传。
-
null ?? 'fallback'→'fallback' -
undefined ?? 'fallback'→'fallback' -
0 ?? 'fallback'→0(不触发) -
'' ?? 'fallback'→''(不触发)
undefined 代表“未定义”,null 代表“有意为空”
这是二者最核心的语义差异,直接影响你该用哪个来初始化变量或设计 API:
-
undefined:系统自动产生。比如变量声明未赋值、函数没写return、对象访问不存在的属性、调用函数时漏传参数。它暗示“这里本该有值,但还没给”。 -
null:开发者主动赋值。比如显式清空用户信息、重置表单字段、标记某个资源“确认不存在”。它暗示“我知道这里有东西,但我决定让它为空”。
所以当你看到 user.profile?.name ?? 'Anonymous',?? 真正在兜底的是 profile 为 null 或 undefined 导致链断裂后产生的 undefined——不管源头是属性没定义(undefined),还是 profile 被设为 null,结果一样。
短路逻辑对副作用的影响一致
?? 是短路运算符:只要左侧不是 null 或 undefined,右侧表达式根本不会执行。这个行为对两者完全对称:
-
getUserId() ?? fallback():如果getUserId()返回undefined,fallback()执行;返回null,同样执行;返回123,fallback()完全不调用。 - 这意味着,无论你用
null还是undefined表示空状态,只要进了??左侧,它们触发的副作用(如函数调用、计算、日志)规则完全相同。
与可选链(?.)配合时,语义差异才真正显现
?? 单独用时不暴露语义,但和 ?. 连用时,null 和 undefined 的来源会影响你是否需要多层防护:
-
obj?.data?.value ?? 'default':只要obj或data是null/undefined,整个链就短路为undefined,再由??接住。 - 但如果
obj.data是null(比如后端明确返回"data": null),而你期望它是个对象,那问题其实在数据建模层面——??只是补救,不是替代类型校验。 - 相比之下,
undefined更常出现在前端运行时缺失(比如异步加载中data还没拿到),这时??提供默认值更自然。









