可选链操作符?.用于安全访问嵌套对象属性,当路径中任一环节为null或undefined时立即返回undefined而不报错;它支持属性访问(obj?.prop)、方法调用(obj?.method())和数组索引(arr?.[0]),但不可用于赋值左侧,且需配合??而非||提供默认值。

可选链操作符 ?. 是目前访问嵌套对象最直接、最安全的语法,只要中间任意一层是 null 或 undefined,整个表达式就立刻返回 undefined,不报错也不继续执行。
什么时候该用 ?. 而不是 && 连写判断
当你需要读取一个可能中途断裂的路径(比如 user.profile.address.city),且这个路径中任一环节都可能缺失时,?. 就比手写 user && user.profile && user.profile.address && user.profile.address.city 更可靠:
-
&&会把0、false、''当作“假值”短路,导致本该存在的合法值被跳过 -
?.只在null或undefined时短路,语义更精准 - 链越长,
?.的可读性优势越明显;三层以上嵌套基本不该再用手动&&
?. 支持的三种访问形式及对应陷阱
它不是只替代 .,而是覆盖了三种常见访问场景,但每种都有易错点:
- 属性访问:
obj?.prop或obj?.['prop-name']—— 方括号形式适合动态 key,但注意不能写成obj?['prop'](少了个点) - 函数调用:
obj?.method()—— 如果method存在但内部抛错,?.不拦截,它只管“是否存在”,不管“是否执行成功” - 数组索引:
arr?.[0]?.name—— 必须对数组本身和首项都加?.,漏掉arr?.[0]中的?.就可能报Cannot read property 'name' of undefined
为什么必须搭配 ?? 而不是 || 用
单独用 ?. 返回的是 undefined,但业务上你往往需要兜底值。这时一定要用空值合并运算符 ??:
-
const city = user?.profile?.address?.city ?? '未知城市'——??只在左侧为null或undefined时生效 - 别写
user?.profile?.address?.city || '未知城市'—— 如果city是0、false、'',也会被替换成兜底值,逻辑就错了 - 如果兜底值本身也要计算(比如调用函数),确保它没有副作用,因为
??是惰性求值,仅当左侧为 null/undefined 时才执行右侧
哪些地方绝对不能用 ?.
它不是万能胶,滥用反而掩盖问题或引发语法错误:
- 不能出现在赋值左侧:
user?.profile = {}是语法错误,?.只用于读取,不用于写入 - 不能用于声明或解构:
const { name } = user?.profile合法,但const { name } = user?.profile ?? {}才真正安全;单纯靠?.不足以让解构免于报错 - 如果某层按接口定义“必须存在”,却还加
?.,说明类型定义或数据契约有问题,该修的是数据源或类型,不是加操作符
真正容易被忽略的是:可选链只解决“访问不存在属性时不报错”,它不校验数据结构合理性,也不处理异步加载中的竞态或中间状态。一旦发现大量 ?. 出现在同一块业务逻辑里,值得回溯——是不是该用类型守卫、默认值初始化,或者重构数据获取方式了。

















