← 返回题目列表

可选链和空值合并运算符解决了什么问题?

高频 简单 第 2 / 28 题 更新于 2026/07/28
ES2020可选链空值合并

简化版

可选链 ?. 用来安全访问可能为空的属性、方法或数组项;空值合并 ?? 只在左侧是 nullundefined 时使用右侧默认值,避免 || 误伤 0、空字符串和 false

详细版

可选链常见写法:

user?.profile?.name
list?.[0]
callback?.()

空值合并常见写法:

const pageSize = input.size ?? 20;

它们经常一起使用:

const city = user?.address?.city ?? '未知';

面试重点是:?. 只在当前访问对象为 null/undefined 时短路,?? 只把 null/undefined 当成缺失值。

完整版教学

一、可选链解决深层属性访问的防御代码

没有可选链时,访问深层字段常写成一串 &&。 这种写法冗长,而且容易把真正有效的假值也混入判断。 可选链把“如果前面为空就停止访问”的意图写得更直接。

const name = user && user.profile && user.profile.name;
const name2 = user?.profile?.name;

如果 usernullname2 会得到 undefined,不会抛出错误。 这对接口数据、配置对象、可选回调非常常见。 但它不是异常吞噬器,它只处理链路中 nullundefined

二、可选链有三种常见形态

可选链不仅能访问对象属性,也能访问数组项和调用函数。 不同形态解决的场景不同。 面试时最好把这三种都说出来,说明自己不是只会背属性访问。

user?.name;       // 属性
users?.[0];       // 下标
onClose?.();      // 函数调用
写法场景为空时结果
obj?.prop对象属性undefined
obj?.[key]动态属性或数组项undefined
fn?.()可选函数调用undefined

函数调用场景很实用。 组件回调不是必传时,用 onSuccess?.(data) 比先写 if (onSuccess) 更紧凑。

三、短路只发生在连续链路上

可选链短路有边界。 如果你用括号把链路截断,后续访问可能继续执行并报错。 这类细节经常出现在笔试题里。

const user = null;

user?.profile?.name; // undefined
(user?.profile).name; // TypeError

第一行是一条连续可选链。 第二行括号先算出 user?.profile,结果是 undefined,然后再访问 .name,于是报错。

连续链路:user ?. profile ?. name -> 中途为空就停
括号截断:(user ?. profile) . name -> 括号后重新访问

所以可选链不能机械添加,要看访问链路是否完整。

四、空值合并解决默认值误判

|| 会把所有假值都当成需要兜底。 但很多业务里 0、空字符串、false 都是合法值。 ?? 只在左侧是 nullundefined 时使用右侧默认值。

const a = 0 || 10;  // 10
const b = 0 ?? 10;  // 0
const c = '' ?? '默认'; // ''
const d = null ?? '默认'; // '默认'

带数字的场景最容易说明差异。 比如分页大小 0 可能表示“不限制”,如果用 || 20 就会被错误改成 20

五、?.?? 经常组合,但职责不同

可选链负责安全取值。 空值合并负责缺失兜底。 它们经常连用,但不能混成同一个概念。

const timeout = config?.request?.timeout ?? 3000;

这个表达式可以拆成两步理解:

先取值:config?.request?.timeout
  -> 取不到得到 undefined
再兜底:undefined ?? 3000
  -> 得到 3000

如果 timeout 明确是 0,结果就是 0。 这比 config && config.request && config.request.timeout || 3000 更符合配置语义。

记忆钩子:?. 管“路上有没有断”,?? 管“结果是不是空值”。

六、语法限制和工程注意点

可选链不能用于所有位置。 比如不能把 obj?.prop 放在赋值左侧。 因为当对象为空时,语言无法知道应该给谁赋值。

// 错误写法
// user?.name = 'Alice';

另外,??||&& 混用时需要用括号明确优先级。 这能避免读者误判,也能满足语法限制。

const value = (a ?? b) || c;

工程实践里,可选链适合读取数据,不适合掩盖数据契约问题。 如果某个字段按协议必须存在,长期使用 ?. 可能会把上游错误隐藏到更晚才暴露。

七、常见误区与追问

  • 误区:可选链会捕获所有异常。 它只在访问对象为 null/undefined 时短路,不会捕获函数内部抛出的错误。
  • 误区:??|| 完全等价。 ?? 只处理 null/undefined|| 会处理所有假值。
  • 误区:用了 ?. 就说明数据结构可以随便缺失。 必填字段缺失仍是数据契约问题,不能全部靠可选链掩盖。
  • 追问:callback?.() 如果 callback 是字符串会怎样? 如果值存在但不是函数,调用仍会报错;可选链不做类型转换。
  • 追问:为什么 user?.profile.name 仍可能报错? 如果 profile 可能为空,就需要写成 user?.profile?.name,每个不确定节点都要标记。
  • 追问:0 ?? 10 || 1 结果为什么不同? 0 不是空值,所以 ?? 保留它;但 0 是假值,所以 || 使用右侧。

八、加强记忆

可选链和空值合并要分开记:?. 是安全走路径,遇到 null/undefined 停下;?? 是结果兜底,只把 null/undefined 当缺失。面试答题时用 0 ?? 20 的分页例子说明它优于 ||,再补连续链路和函数调用的边界。