JavaScript 中 ?? 与 || 的核心区别与实战指南

53 阅读3分钟

在 JavaScript 中,??(空值合并运算符)和 ||(逻辑或运算符)都常用于处理变量的默认值场景,但两者的行为逻辑存在关键差异。误用可能导致意想不到的 bug,本文将深入解析它们的区别与正确用法。

一、基础定义与行为对比

1. 空值合并运算符(??)

核心逻辑:仅当左侧操作数为 null 或 undefined 时,返回右侧操作数;否则返回左侧操作数。

javascript

运行

// 左侧为 null/undefined 时,返回右侧
const a = null ?? "默认值"; // "默认值"
const b = undefined ?? "默认值"; // "默认值"

// 左侧为其他值(即使是假值),返回左侧
const c = 0 ?? 100; // 0(0 不是 null/undefined)
const d = "" ?? "空字符串"; // ""(空字符串有效)
const e = false ?? true; // falsefalse 是有效布尔值)

2. 逻辑或运算符(||)

核心逻辑:当左侧操作数为「假值」时,返回右侧操作数;否则返回左侧操作数。
(JavaScript 中的假值包括:false0""nullundefinedNaN

javascript

运行

// 左侧为假值时,返回右侧
const f = 0 || 100; // 100(0 是假值)
const g = "" || "默认字符串"; // "默认字符串"(空字符串是假值)
const h = null || "非空"; // "非空"(null 是假值)

// 左侧为真值时,返回左侧
const i = "hello" || "world"; // "hello"
const j = 10 || 20; // 10

二、核心区别深度解析

维度空值合并运算符(??)逻辑或运算符(??)
判断标准仅检查 null/undefined 检查所有「假值」(6 种)
适用场景保留 0、"" 等有效假值的场景需要过滤所有假值的场景
类型转换不进行类型转换,直接比较原始值会隐式转换左侧值为布尔类型判断
优先级较低(与 || 不同,需注意括号使用)高于 ??(混合使用需加括号)

三、实战场景中的选择指南

1. 何时用??:需要保留 0 或空字符串的场景

  • 处理数字输入(如数量、分数可能为 0)
  • 处理文本输入(如空字符串可能是有效输入)

javascript

运行

// 示例:用户输入年龄为 0(有效)
const ageInput = 0;
const displayAge = ageInput ?? "未知"; // 正确显示 0

// 错误用法(用 || 会把 0 当成无效值)
const wrongAge = ageInput || "未知"; // "未知"(错误)

2. 何时用 ||:需要过滤所有无效值的场景

  • 处理配置项(仅保留有效配置)
  • 处理可选参数(排除所有假值)

javascript

运行

// 示例:过滤无效的配置值
const config = {
  timeout: 0, // 0 是有效配置(表示立即超时)
  logLevel: "" // 空字符串是无效配置
};

// 正确:logLevel 为空字符串时使用默认值
const effectiveLogLevel = config.logLevel || "info"; 

// 正确:timeout 为 0 时应保留(用 ??)
const effectiveTimeout = config.timeout ?? 5000; 

四、注意事项与常见陷阱

1. 优先级问题:?? 与 &&/|| 混合使用需加括号

?? 的优先级低于 && 和 ||,直接混合使用会报错,必须用括号明确优先级:

javascript

运行

// 错误写法(语法错误)
const result = 1 || 2 ?? 3;

// 正确写法(用括号明确逻辑)
const result1 = (1 || 2) ?? 3; // 1
const result2 = 1 || (2 ?? 3); // 1

2. 与可选链运算符(?.)的配合

?? 常与 ?. 配合处理深层对象属性,安全获取默认值:

javascript

运行

const user = { name: "" };

// 安全获取用户年龄(若不存在则用默认值 18)
const age = user?.age ?? 18; // 18

// 保留空字符串姓名(不替换为默认值)
const name = user?.name ?? "匿名用户"; // ""(正确,空字符串是有效姓名)

3. 浏览器兼容性

?? 是 ES2020 新增特性,现代浏览器(Chrome 80+、Firefox 72+、Edge 80+)均支持,但旧环境(如 IE)需通过 Babel 转译。

五、总结

  • ?? 是「空值保护符」:只对 null/undefined 生效,适合保留 0、空字符串等有效假值的场景。
  • || 是「假值过滤器」:对所有假值生效,适合需要排除任何无效值的场景。

记住:当你需要「只有值完全不存在时才用默认值」,选 ??;当你需要「值无效时就用默认值」,选 ||。合理选择能避免大量边界场景的 bug。