原文链接:Logical assignment operators in JavaScript: small syntax, big wins,2025.07.28,by Matt Smith。
在日常的 JavaScript 开发中,我们经常需要先检查变量再为其赋值。不过在 JavaScript 中这种检查会很繁琐,尤其是在处理组件属性(component props)、全局配置(global configs)或状态对象(state objects)时。这时,逻辑赋值运算符(logical assignment operators) 就派上用场了——它是ES2021中新增的一个简洁特性,能简化常见的条件赋值操作,同时不改变底层逻辑。
什么是逻辑赋值运算符?
逻辑赋值运算符将逻辑运算符(||、&&或??)与赋值运算符(=) 结合,提供一种简写形式。这些运算符和常规的逻辑表达式一样支持短路求值(short-circuit),也就是说只有当左侧不符合测试条件(即为假值、真值或空值)时,才会对右侧进行求值。
⚠️ 注意:可选链(Optional chaining,?.)不允许用于逻辑赋值的左侧,否则会抛出语法错误:
// ❌ 语法错误:
user?.settings ||= {};
可选链返回的是属性访问的结果,而非属性本身的引用。由于赋值目标必须是引用(即变量或对象属性),所以上述写法是无效的。
逻辑或赋值(||=)
当左侧为假值(falsy) 时赋值:
user.theme ||= 'light';
等价于:
if (!user.theme) {
user.theme = 'light';
}
这在没有初始化值的场景设置默认值时很有用。但是,它会覆盖像0、''或false这类可能是有意设置的值。
逻辑与赋值(&&=)
当左侧为**真值(truthy)**时赋值:
user.isLoggedIn &&= checkPermissions(user);
等价于:
if (user.isLoggedIn) {
user.isLoggedIn = checkPermissions(user);
}
这有助于根据已有的真值条件更新值。
⚠️ 注意:使用&&=时,只有当左侧为真值时才会对右侧求值,并将右侧的实际结果赋值给左侧,即便该结果是假值也不例外。
let isEnabled = true;
isEnabled &&= false;
console.log(isEnabled); // false
原始值(true)起到了“ gate”的作用,但最终是右侧表达式的结果成为新值。&&=不会保留旧值,而是直接替换它。
空值合并赋值(??=)
当左侧为空值(null或undefined)时赋值:
settings.timeout ??= 3000;
等价于:
if (settings.timeout === null || settings.timeout === undefined) {
settings.timeout = 3000;
}
当你只想在值确实缺失时赋值默认值,就可以使用这个运算符。与||=不同,它会保留0、false和''这类有效的值。
为什么逻辑赋值在代码中很重要?
这些运算符不只是语法糖。它们能更安全、更易读地解决实际问题,尤其是在处理可变状态(mutable state)时:
这些运算符会直接修改原始对象或变量。这在有状态逻辑中可能很有用,但在不可变工作流(如Redux)中可能会导致错误。如果需要保留状态历史,需要先克隆对象。
为组件属性设置默认值
props.showHelpText ??= true;
避免覆盖全局状态或配置
config.apiBase ||= '/api/v1';
防止意外的null/undefined赋值
formData.username &&= formData.username.trim();
但要注意
||=会在左侧为假值时赋值,这会覆盖包括0、''和false在内的场景,而这些值可能是你想要保留的。
let count = 0;
count ||= 10; // 会将count覆盖为10,要小心!
- 当你想专门针对
null或undefined进行防护,并保留有效的假值时,使用??=。 - 右侧表达式仅在必要时才会求值,这样能保证性能并避免副作用。
config.apiKey ||= fetchApiKey(); // 只有当apiKey为假值时,才会执行fetchApiKey()
带有副作用的示例
let calls = 0;
let obj = { val: 0 };
obj.val ||= ++calls;
console.log(obj.val); // 1,因为0是假值
obj.val ||= ++calls;
console.log(obj.val); // 仍然是1,第二次递增不会执行
由于obj.val最初是0(假值),所以会对++calls求值并赋值。在第二次执行时,obj.val现在是1(真值),因此++calls会被跳过。calls的值仍然是1。
浏览器支持情况
逻辑赋值运算符在所有现代环境中都得到支持:
- ✅ Chrome 85+、Firefox 79+、Safari 14+、Edge 85+
- ✅ Node.js 15+
- ❌ 不支持Internet Explorer
如果要兼容旧环境,可以使用@babel/preset-env这类转译工具,并配置ES2021设置。
现在就可以使用了
逻辑赋值运算符是JavaScript中一个虽小但强大的新增特性。它们能明确你的语义意图,减少样板代码,并简化常见的条件逻辑。
在前端工作流中,它们尤其有用,例如:
- 属性和状态管理
- API默认值设置
- 表单整理
如果你已经熟练使用||、&&和??,那么掌握||=、&&=和??=对大家来说只是水到渠成的事。