`??` 和 `||` 搞混,线上客户头像全挂了 问题场景 上周五快下班,客服群突然炸了: "好多用户头像显示空白!" "不是全部,大概 30% 的账号头像没了" 查前端日志,头像接口返回正常, url 字段有值。再看渲染层代码: const avatarUrl = user. avatar ?. url || '/default-avatar.png' 逻辑看似没毛病:有头像用头像,没有就用默认图。但诡异的是, 有头像的用户也显示了默认图 。 原因研判 问题出在 || 运算符的"激进"行为上。 || 会把所有 假值 (falsy) 都当成"没有"来对待。JavaScript 中的假值包括: 值 类型 '' 空字符串 0 数字零 false 布尔假 null 空 undefined 未定义 NaN 非数字 排查后发现,这批头像异常的用户的 url 值刚好是 空字符串 '' — 头像服务在某些情况下会返回 url: "" (代表用户上传过头像但处理失败)。 // 实际资料 user. avatar = { url : '' } // 空字符串,但 ≠ 没头像 // 执行逻辑 const avatarUrl = '' || '/default-avatar.png' // → 空字符串是假值,被 || 吞掉,返回默认图 ❌ 用户明明上传过头像(数据库有记录),只是因为图片处理失败返回了空串,就被 || 强制替换成默认图——这就成了"有头像但显示默认"的 bug。 应对方案 方案一:改用 ?? (空值合并运算符) const avatarUrl = user. avatar ?. url ?? '/default-avatar.png' ?? 只会在左操作数为 null 或 undefined 时才取右侧值。 '' 、 0 、 false 都会原样保留。 注意: ?? 不能与 && 或 || 混用不括弧: // ❌ 语法错误 const a = b ?? c || d // ✅ 正确写法 const a = (b ?? c) || d 方案二:显式判断 const avatarUrl = user. avatar ?. url && user. avatar . url . length > 0 ? user. avatar . url : '/default-avatar.png' 更保险,但啰嗦。 方案三:后端统一语义 后端对 url 字段做约束:没有头像 → 不返回字段或返回 null ;有头像(包括处理失败)都正确定义。前端只信任 ?? 。 深入:还有哪些地方容易踩? 场景 1:分数/数值 0 // 用户完成了 0 道题 const count = data. completedCount || '无数据' // 0 被 || 吞掉,显示"无数据" ❌ const count = data. completedCount ?? '无数据' // ✅ 显示 0 场景 2:CSS class 拼接 // 某个状态的 className 可能是空串 '' const cls = statusClass || 'default-status' // 空串时被覆盖 ❌ const cls = statusClass ?? 'default-status' // ✅ 场景 3:函数默认参数 function setTheme ( color = '#333' ) { ... } setTheme ( '' ) // '' 是假值吗?不,函数默认参数只对 undefined 生效 // → 传入 '' 不会触发默认值,color = '' 函数默认参数的行为类似 ?? ,只对 undefined 生效。很多人误以为它和 || 一样。 要点总结 运算符 触发替换的条件 适用场景 ?? null / undefined 后端可能缺失的字段、可选链取值 ` ` 所有假值 兜底默认值(明确想过滤空串/0) 函数默认参数 仅 undefined 参数缺省传值 一句话黄金法则: 当你要表达"没有这个数据就用默认值"时,99% 的场景应该用 ?? ; 只有 1% 的场景(如用户输入为空时填默认文案)才刻意用 || 。 修完这个 bug 后的复盘会上,全组把 eslint 加了一条规则: // .eslintrc { "rules" : { "no-unneeded-ternary" : "error" , "@typescript-eslint/prefer-nullish-coalescing" : "error" } } 并在代码 review checklist 里写死了一条: "见到 || 接变量,先想想是不是应该用 ??" 。 从此,头像空白 bug 再没出现过。
- 上一篇 > `??` 和 `||` 搞混,线上使用者头像全挂了
- 下一篇 > 前端给AI消息做日期分组与时间线

