JavaScript作为一门不断发展的语言,总是在引入新特性来解决开发者的痛点。其中,ES2020引入的空值合并操作符(Nullish Coalescing Operator),即双问号操作符(??),是一个简单却极其强大的工具,彻底改变了我们处理默认值和空值的方式。
1. 基本概念:什么是??操作符
双问号操作符(??)是一个逻辑操作符,当左侧操作数为null或undefined时,返回右侧操作数,否则返回左侧操作数。这看似简单,但与我们常用的逻辑或操作符(||)有着本质区别。
const value1 = null ?? 'default'; // 'default'
const value2 = undefined ?? 'default'; // 'default'
const value3 = false ?? 'default'; // false
const value4 = 0 ?? 'default'; // 0
const value5 = '' ?? 'default'; // ''
2. ??与||的关键区别
在了解??操作符的强大之前,我们需要理解它与||操作符的区别:
// 使用||
const count = userCount || 10; // 当userCount为0时,count将为10
// 使用??
const count = userCount ?? 10; // 当userCount为0时,count将为0
||操作符会将所有"假值"(如0、''、false、NaN等)都视为需要使用默认值的情况,而??操作符只在值为null或undefined时才使用默认值。
3. 实际应用
(1) 表单处理中的默认值
function processForm(data) {
// 只有当值真正缺失时才使用默认值
const username = data.username ?? 'guest';
const items = data.items ?? [];
const quantity = data.quantity ?? 1; // 允许quantity为0
// 处理表单逻辑...
}
(2) 配置对象的深层默认值
const config = {
server: {
port: 0, // 有效值,但为"假值"
host: '' // 有效值,但为"假值"
}
};
const userConfig = {};
// 正确处理深层配置
const port = userConfig?.server?.port ?? config.server.port; // 0
const host = userConfig?.server?.host ?? config.server.host; // ''
(3) API响应处理
(4) 链式默认值
??操作符可以链式使用,创建一个"默认值瀑布":
(5) 与可选链操作符(?.)完美配合
当与可选链操作符(?.)结合使用时,处理复杂嵌套对象变得异常优雅:
const userName = user?.profile?.preferences?.displayName ?? 'Guest';
这行代码可以安全地深入访问一个可能不存在的嵌套属性,并在任何一层为null或undefined时提供默认值。
(6) 条件性执行函数
// 仅当handler存在时才执行,否则使用默认处理函数
(customHandler ?? defaultHandler)(event);
(7) 数组元素的默认值处理
4. 高级技巧
(1) 结合解构赋值
const { name, age, title = 'Developer', company = 'Unknown' } = employee ?? {};
这个模式不仅能处理employee为null/undefined的情况,还为解构出的个别属性提供默认值。
(2) 在类中使用
class UserPreferences {
constructor(settings) {
this.theme = settings?.theme ?? 'light';
this.fontSize = settings?.fontSize ?? 16;
this.notifications = settings?.notifications ?? true;
// 即使settings.volume为0也会被保留
this.volume = settings?.volume ?? 0.5;
}
}
5. 性能考虑
??操作符不仅语法简洁,在某些情况下还能带来性能优势。由于它只检查null和undefined,比||操作符的类型转换操作更高效。
双问号操作符(??)虽然看似简单,却解决了JavaScript中一个长期存在的痛点:如何正确处理"空值"与"假值"的区别。