ES 空值合并运算符??与可选链?.的使用小结

 更新时间:2026年03月18日 09:19:14   作者:兆子龙  
本文主要介绍了ES 空值合并运算符??与可选链?.的使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

掌握这两个语法糖,写出更优雅的 JavaScript 代码。

一、为什么需要??和?.

在日常开发中,我们经常需要处理变量可能为 nullundefined 的情况。传统的做法是使用逻辑或运算符 || 来提供默认值,但这种做法有一个隐蔽的陷阱。

const count = 0;
const total = count || 10;
console.log(total); // 输出 10,而不是预期的 0

上面的代码中,count 的值是 0,这是一个有效的数值,但 || 会把它当作「假值」处理,返回默认值 10。这显然不是我们想要的结果。

空值合并运算符 ?? 和可选链 ?. 的出现,正是为了解决这类问题。它们只会在值为 nullundefined 时才进行默认值的处理,而不会误伤 0false'' 这样的「假值」。

二、空值合并运算符??

2.1 基本用法

空值合并运算符 ?? 会在左侧表达式值为 nullundefined 时返回右侧的默认值,否则返回左侧的值。

const count = 0;
const total = count ?? 10;
console.log(total); // 输出 0,正确!

const name = null;
const displayName = name ?? 'Anonymous';
console.log(displayName); // 输出 'Anonymous'

const age = undefined;
const userAge = age ?? 18;
console.log(userAge); // 输出 18

2.2 与||的区别

让我们通过一个对比表格来清晰展示两者的区别:

| 左侧值 | a ?? b 结果 | a || b 结果 | |--------|---------------|---------------| | null | b | b | | undefined | b | b | | 0 | 0 | b | | false | false | b | | '' | '' | b | | 'hello' | 'hello' | 'hello' |

从表格可以看出,?? 只会对 null 和 undefined 「过敏」,而 || 会对所有假值过敏。在需要保留 0、false、'' 这样的有效值的场景下,?? 是更安全的选择。

2.3 链式使用

?? 可以链式使用,但需要注意优先级问题:

const a = null;
const b = undefined;
const c = 0;
const d = '';

const result1 = a ?? b ?? c ?? 'default';
console.log(result1); // 输出 0

const result2 = a ?? b ?? d ?? 'default';
console.log(result2); // 输出 ''

链式使用时,?? 会从左到右找到第一个非 null/undefined 的值就返回。

2.4 注意事项

?? 不能与 && 或 || 直接混用,需要使用括号明确优先级:

// 错误写法 - 会抛出 SyntaxError
const invalid = null || undefined ?? 'default';

// 正确写法 - 使用括号明确优先级
const valid1 = (null || undefined) ?? 'default';
const valid2 = null || (undefined ?? 'default');

三、可选链?.

3.1 基本用法

可选链运算符 ?. 允许你安全地访问嵌套对象的属性,即使中间某个属性不存在也不会报错。

const user = {
  name: 'Alice',
  address: {
    city: 'Beijing'
  }
};

// 传统写法 - 需要先判断每一层
const city1 = user && user.address && user.address.city;

// 使用可选链 - 简洁安全
const city2 = user?.address?.city;
console.log(city2); // 输出 'Beijing'

// 访问不存在的属性
const country = user?.address?.country;
console.log(country); // 输出 undefined,不会报错

3.2 多种用法

可选链不仅可以用在属性访问上,还支持方法调用和数组索引:

// 方法调用
const result = obj?.method?.();

// 数组索引
const firstItem = arr?.[0];

// 动态属性名
const value = obj?.[key];

3.3 实际应用场景

在实际开发中,可选链特别适合处理以下场景:

// 1. 处理表单数据
const formData = {
  user: {
    profile: {
      name: 'Bob'
    }
  }
};

// 安全获取用户名,即使中间某层不存在
const userName = formData?.user?.profile?.name ?? 'Guest';

// 2. 处理 API 响应
async function fetchUser() {
  const response = await fetch('/api/user');
  const data = await response.json();
  
  // 安全访问嵌套数据
  const email = data?.user?.contact?.email ?? 'no-email';
  const avatar = data?.user?.profile?.avatar ?? '/default-avatar.png';
  
  return { email, avatar };
}

// 3. 处理可选的回调函数
function handleClick(event) {
  // 某些情况下 onClick 可能未定义
  event?.preventDefault?.();
  callback?.(event);
}

3.4 短路求值

可选链具有短路求值的特性:如果 ?. 左侧的值为 null 或 undefined,右侧的表达式不会被执行。

const obj = null;
let count = 0;

// 不会执行,因为 obj 为 null
const result = obj?.method(() => count++);

console.log(count); // 输出 0,callback 没有被执行

这个特性在包含副作用的表达式中特别有用,可以避免不必要的函数调用。

四、组合使用?.??

?. 和 ?? 可以组合使用,处理更复杂的场景:

const config = {
  database: {
    host: null,
    port: 5432
  }
};

// 安全获取数据库配置,主机为空时使用默认值
const dbHost = config?.database?.host ?? 'localhost';
const dbPort = config?.database?.port ?? 3306;

console.log(dbHost); // 输出 'localhost'
console.log(dbPort); // 输出 5432

// 处理深层嵌套的配置对象
const settings = {
  ui: {
    theme: {
      colors: null
    }
  }
};

const primaryColor = settings?.ui?.theme?.colors?.primary ?? '#1890ff';
console.log(primaryColor); // 输出 '#1890ff'

五、TypeScript 中的使用

在 TypeScript 中使用 ?? 和 ?. 时,类型系统能够正确推断出可能的类型:

interface User {
  name: string;
  address?: {
    city: string;
    zipCode?: string;
  };
}

const user: User = {
  name: 'Alice'
};

// 可选链返回 undefined 或 string,类型为 string | undefined
const city = user.address?.city;

// 空值合并确保最终类型为 string
const zipCode = user.address?.zipCode ?? '000000';

六、浏览器兼容性

截至 2026 年,?? 和 ?. 已经在所有主流浏览器中得到支持,包括 Chrome、Firefox、Safari 和 Edge 的最新版本。对于需要兼容旧版浏览器的项目,可以使用 Babel 或 TypeScript 进行转译。

// .babelrc 或 babel.config.js
{
  "plugins": [
    "@babel/plugin-proposal-optional-chaining",
    "@babel/plugin-proposal-nullish-coalescing-operator"
  ]
}

七、常见误区

第一个误区是认为 ?? 可以完全替代 ||。实际上,|| 在需要区分「未设置」和「设置了假值」的场景下仍然有用。比如表单验证中,空字符串可能是一个有效的输入值。

第二个误区是过度使用可选链。虽然可选链很方便,但在确定某属性一定存在的情况下,使用普通属性访问(.)性能更好,代码意图也更清晰。

第三个误区是在条件判断中混用 ?? 和 &&/||。由于运算符优先级不同,混用时必须使用括号来明确意图。

总结

?? 和 ?. 是 ES2020 引入的两个非常实用的语法糖。?? 解决了 || 在处理假值时的误伤问题,?. 让深层嵌套对象的访问变得安全简洁。合理使用这两个特性,可以让你的 JavaScript 代码更加健壮和优雅。

到此这篇关于ES 空值合并运算符??与可选链?.的使用小结的文章就介绍到这了,更多相关 ES空值合并运算符??与可选链?.内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • Html中JS脚本执行顺序简单举例说明

    Html中JS脚本执行顺序简单举例说明

    写在最前面的最先执行,Body的onload事件要在页面加载完后才执行。
    2010-06-06
  • JSONP原理及简单实现

    JSONP原理及简单实现

    这篇文章主要介绍了JSONP原理及简单实现的相关资料,非常不错具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • JS的事件绑定深入认识

    JS的事件绑定深入认识

    类似于JQuery的这样js库已经实现了很好的数据绑定机制的封装效果,但只知其然,不知其所以然还有会有种蒙在鼓里的感觉,亲自去分析一下具体的实现,会有一种豁然开朗的感觉
    2014-06-06
  • Webpack中实现条件组件的按需打包的多种方法

    Webpack中实现条件组件的按需打包的多种方法

    按需加载是优化性能的重要手段,本文主要介绍了Webpack中实现条件组件的按需打包的示例,帮助你显著减少初始包体积,提升应用加载速度,感兴趣的可以了解一下
    2025-06-06
  • JS实现图片元素转BASE64编码的简单示例

    JS实现图片元素转BASE64编码的简单示例

    在Web开发中,我们经常需要将图片转换为Base64格式,以便在不依赖外部资源的情况下直接在HTML中使用,在这篇文章中,我将向您展示如何使用JavaScript将图片元素转BASE64编码,需要的朋友可以参考下
    2023-12-12
  • 纯JS开发baguetteBox.js响应式画廊插件

    纯JS开发baguetteBox.js响应式画廊插件

    这篇文章主要介绍了纯JS开发baguetteBox.js响应式画廊插件,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • 微信小程序swiper禁止用户手动滑动代码实例

    微信小程序swiper禁止用户手动滑动代码实例

    这篇文章主要介绍了微信小程序swiper禁止用户手动滑动代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • 学习并汇集javascript匿名函数

    学习并汇集javascript匿名函数

    接触jQuery很长时间了,对其的实现有太多疑问,可谓只知道皮毛,对其的精髓一窍不通,可悲啊!所以有必要研究下其中的原理。
    2010-11-11
  • 如何基于viewport vm适配移动端页面

    如何基于viewport vm适配移动端页面

    这篇文章主要介绍了如何基于viewport vm适配移动端页面,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • JavaScript调用麦克风录音完整实现步骤

    JavaScript调用麦克风录音完整实现步骤

    在JavaScript中调用手机的录音功能是我最近遇到的一个需求,下面这篇文章主要介绍了JavaScript调用麦克风录音的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-10-10

最新评论