??运算符仅在左侧为null或undefined时返回右侧默认值,不处理其他假值;需配合?.操作符才能安全访问嵌套属性,避免空指针异常。

空值合并运算符 ?? 本身不“处理” null 和 undefined 引发的运行时错误,它只在左侧值为 null 或 undefined 时提供默认值;真正防止空指针异常(如 Cannot read property 'x' of null)的关键,是配合可选链操作符 ?. 使用。
?? 的核心作用:精准兜底,不越界
?? 只做一件事:当且仅当左侧表达式的结果是 null 或 undefined 时,返回右侧默认值。它对其他假值(0、false、''、NaN)完全无感,会原样保留。
-
user?.name ?? 'Anonymous'✅ 安全:先用?.避免访问user.name报错,再用??处理可能的undefined -
user.name ?? 'Anonymous'❌ 危险:若user是null,代码在执行到user.name时就已崩溃,??根本没机会运行 -
config?.timeout ?? 5000✅ 即使config未定义,也不会报错,最终得到5000
安全访问嵌套属性的标准写法
面对多层嵌套(如 data.items[0].title),必须逐级使用 ?. ,再在末尾用 ?? 设默认值:
-
data?.items?.[0]?.title ?? 'No title'—— 每一层都静默失败,只在最后取值阶段兜底 -
user?.profile?.settings?.theme ?? 'light'—— 任一环节为null/undefined都不会中断,结果确定可控 -
response?.data?.user?.id ?? null—— 明确区分“字段不存在”和“字段存在但值为null”
与 || 的关键区别:别让 0 和 false 被误覆盖
用 || 设默认值容易引发逻辑错误,因为它的判断依据是“是否为 falsy”,而 ?? 只认 null/undefined:
-
count = obj?.count ?? 10→ 若obj.count === 0,结果是0(合理) -
count = obj?.count || 10→ 若obj.count === 0,结果却是10(掩盖了真实意图) -
isActive = user?.active ?? true→false会被保留,表示明确禁用 -
isActive = user?.active || true→false也会触发回退,变成true(语义错误)
常见误用提醒
这些写法看似简洁,实则隐藏风险或违背设计初衷:
-
obj.prop ?? 'default':没加?.,一旦obj是null就报错 -
arr?.[0] ?? []:如果想默认是空数组,应写成arr?.[0] ?? [],但注意这返回的是第一个元素,不是整个数组;若需默认空数组,应是arr ?? [] -
value ?? 'default' ?? 'backup':语法合法但无意义,??是左结合,等价于(value ?? 'default') ?? 'backup',第二个??永远不会生效 -
foo ?? bar || baz:优先级易混淆,实际等价于foo ?? (bar || baz),建议写成(foo ?? bar) || baz明确意图


















