在 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; // false(false 是有效布尔值)
2. 逻辑或运算符(||)
核心逻辑:当左侧操作数为「假值」时,返回右侧操作数;否则返回左侧操作数。
(JavaScript 中的假值包括:false、0、""、null、undefined、NaN)
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。