JavaScript双问号(??)操作符用法详解

 更新时间:2025年04月08日 11:01:12   作者:watermelo37  
在现代JavaScript开发中,处理变量默认值是一个常见但容易引发bug的操作,很多开发者可能都遇到过这样的问题:使用||设置默认值时,意外覆盖了0、''等合法值,这时候,ES2020引入的双问号操作符(??)就能完美解决这类问题,本文将带您全面掌握这个操作符的使用场景和高级技巧

一、双问号操作符??的基础用法

1、传统方式的痛点

const count = 0;
const result = count || 10; // 得到10,但0可能是有效值

使用||时,会把所有假值 (falsy values)视为无效值,包括:0、''、false、NaN、null、undefined。这在处理数字表单、开关状态等场景时会引发问题。

以上述案例来说,我想要count被赋值的情况下就使用count的值,要是没有被赋值就使用默认值10,但是当count被初始化并赋值为0的时候,逻辑或操作符||依然会认为是无效值,并将result赋值为10,这显然和我预期的结果相悖。这是因为JavaScript是一门弱类型语言,会进行强制类型转换。

2、双问号操作符??的精确判断

同样还是这个例子:

const count = 0;
const result = count ?? 10; // 得到0,完美保留有效值

此时result的结果就是10,因为??操作符只对null和undefined这两个原始值进行判断,其他假值都会被保留。这种特性使其特别适合处理以下场景:

  • 表单输入值(允许0或空字符串)
  • 布尔类型配置项
  • 数字类型参数(允许0)

3、双问号操作符??与逻辑或操作符||的对比

特性?? 操作符 || 操作符
触发条件

仅 null/undefined

所有假值
适用场景精准空值判断快速默认值设置
处理 0 和 ''保留有效值覆盖为默认值
处理 false保留布尔值覆盖为默认值

二、复杂场景下的空值处理

1、深层嵌套对象的默认值

结合可选链操作符(?.),可以安全地处理多层嵌套对象的属性访问。

const config = {
  api: {
    v1: {
      endpoint: ''
    }
  }
};
 
// 传统写法(需要逐层判断)
const endpoint = config.api?.v1?.endpoint || 'default';
 
// 使用??的改进写法
const endpoint = config.api?.v1?.endpoint ?? 'default';

2、函数参数的默认值陷阱

当函数参数需要接收布尔值时,使用??可以避免意外覆盖用户传入的false值。

function createPost(data) {
  // 错误写法:会覆盖有效布尔值
  const isPublic = data.isPublic || true;
  
  // 正确写法:仅处理null/undefined
  const isPublic = data.isPublic ?? true;
}

3、多条件回退策略

通过链式使用??,可以实现多层级的配置回退机制,这种模式在读取环境变量时特别实用。

const theme = userConfig.theme 
  ?? systemConfig.theme 
  ?? process.env.THEME 
  ?? 'light';

三、实战案例解析

1、Vue组件中的Prop处理

如果disabled接收的值为false,如果使用逻辑或操作符,就会被认为是无效值,从而使用默认的true值。如果使用双问号操作符就可以避免这种情况。

<template>
  <input :disabled="isDisabled" />
</template>
 
<script>
export default {
  props: {
    disabled: {
      type: Boolean,
      default: undefined
    }
  },
  computed: {
    isDisabled() {
      return this.disabled ?? true;
    }
  }
}
</script>

2、表单验证

就算你不允许用户输入空格,起码要允许用户输入0和引号吧?如果使用逻辑或操作符,根本无法通过表单验证,使用双问号操作符就可以避免这种情况。

function validateForm(formData) {
  const errors = [];
  
  if (formData.username?.trim() ?? false) {
    errors.push('用户名不能为空');
  }
  
  if (formData.age ?? false) {
    errors.push('年龄必须填写');
  }
  
  return errors;
}

四、双问号操作符的性能优势

实际测试显示,??在性能上与||基本持平,但在处理复杂对象时更具优势。这是因为双问号操作符只检查null和undefined,比||操作符的类型转换操作更高效。

当然,这部分差异很小,更多的作用是展示开发者的思维能力。

// 测试环境:Chrome 112,100万次运算
console.time('||');
for (let i = 0; i < 1000000; i++) null || 10;
console.timeEnd('||'); // 2.1ms
 
console.time('??');
for (let i = 0; i < 1000000; i++) null ?? 10;
console.timeEnd('??'); // 1.8ms

五、结语

双问号操作符(??)这个看似简单的语法糖,实则蕴含着提升代码健壮性的强大能力。在实际项目中,建议结合TypeScript的严格空值检查,构建更可靠的类型安全体系。

拓展:双问号(??)和或运算符(||)的区别和使用

1.?? 和 || 的区别

在 JavaScript 中,双问号(??)和或运算符(||)都可以用来设置默认值,但是它们处理 Falsy 值的方式不同。

|| 运算符在遇到 Falsy 值时会返回第一个真值(Truthy)操作数,否则返回最后一个操作数。例如:

const x = null;
const y = x || "default";
console.log(y); // "default"

在上面的代码中,变量 y 的值将是 “default”,因为 x 的值为 null,null 是一个 Falsy 值,所以 y 的值返回了 “default”。

而双问号运算符(??)只在左侧的值为 null 或 undefined 时返回右侧的值,否则返回左侧的值。例如:

const x = null;
const y = x ?? "default";
console.log(y); // null

在上面的代码中,变量 y 的值将是 null,因为 x 的值为 null,而 ?? 运算符只会在左侧的值为 null 或 undefined 时返回右侧的默认值。

因此,双问号运算符和或运算符的区别在于它们在处理 Falsy 值时的行为不同。或运算符会将 Falsy 值视为假,而双问号运算符只在左侧的值为 null 或 undefined 时才返回右侧的默认值。

在实际使用中,当需要设置默认值时,可以使用双问号运算符来避免将 Falsy 值视为默认值。例如:

const x = 0;
const y = x ?? 42;
console.log(y); // 0

在上面的代码中,变量 y 的值将是 0,因为 x 的值为 0,而 0 不是 Falsy 值,所以 y 的值返回了 0。如果使用或运算符来设置默认值,那么 y 的值将会是 42,这可能不是我们期望的结果。

总之,双问号运算符可以更加准确地设置默认值,避免将 Falsy 值视为默认值。

2.?? 和 || 的使用

在 JavaScript 中,双问号(“??”)被称为 Nullish Coalescing 运算符,它用于处理变量值为 null 或 undefined 的情况。

具体来说,双问号运算符返回其左侧的操作数,如果它的值是 null 或 undefined,则返回右侧的操作数。例如:

const x = null;
const y = x ?? "default";
console.log(y); // "default"

在上面的代码中,变量 y 的值将是 “default”,因为 x 的值为 null,而双问号运算符会返回右侧的默认值。

请注意,双问号运算符仅在其左侧的值为 null 或 undefined 时才返回右侧的默认值。如果左侧的值为 “”(空字符串)、0 或 false,则左侧的值仍然被视为有效值,双问号运算符不会返回右侧的默认值。

例如:

const a = "";
const b = a ?? "default";
console.log(b); // ""

在上面的代码中,变量 b 的值将是 “”,因为 a 的值为 “”,而双问号运算符会将其视为有效值,不会返回右侧的默认值。

以上就是JavaScript双问号(??)操作符用法详解的详细内容,更多关于JavaScript双问号??用法的资料请关注脚本之家其它相关文章!

相关文章

  • JavaScript 中 JSON.parse 函数 和 JSON.stringify 函数

    JavaScript 中 JSON.parse 函数 和 JSON.stringify 函数

    这篇文章主要介绍了JavaScript -- JSON.parse 函数 和 JSON.stringify 函数,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-12-12
  • JS+CSS实现的经典tab选项卡效果代码

    JS+CSS实现的经典tab选项卡效果代码

    这篇文章主要介绍了JS+CSS实现的经典tab选项卡效果代码,通过简单的鼠标事件触发js函数实现针对页面元素的遍历与样式变换功能,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-09-09
  • 怎么理解wx.navigateTo的events参数使用详情

    怎么理解wx.navigateTo的events参数使用详情

    这篇文章主要介绍了怎么理解wx.navigateTo的events参数使用详情,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • 详解如何替换项目中的if-else和switch

    详解如何替换项目中的if-else和switch

    这篇文章主要为大家介绍了详解如何替换项目中的if-else和switch,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • ES6 Array常用扩展的应用实例分析

    ES6 Array常用扩展的应用实例分析

    这篇文章主要介绍了ES6 Array常用扩展的应用,结合实例形式分析各种常见扩展方法针对Array数组的转换、遍历、查找、运算等相关操作技巧,需要的朋友可以参考下
    2019-06-06
  • Bootstrap每天必学之栅格系统(布局)

    Bootstrap每天必学之栅格系统(布局)

    Bootstrap每天必学之栅格系统,小编对Bootstrap栅格系统(布局)也很陌生,特分享整理这篇文章,感兴趣的小伙伴们可以参考一下
    2015-11-11
  • clipboard.js在移动端复制失败的解决方法

    clipboard.js在移动端复制失败的解决方法

    最近在使用clipboard.js碰到的一个小问题,通过查找相关资料解决了,所以下面这篇文章主要给大家介绍了关于clipboard.js在移动端复制失败的解决方法,需要的朋友可以参考借鉴,下面来一起学习学习吧
    2018-06-06
  • javascript跨域的方法汇总

    javascript跨域的方法汇总

    JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦。这里把涉及到跨域的一些问题简单地整理一下
    2015-10-10
  • JavaScript实现的鼠标跟随特效示例【2则实例】

    JavaScript实现的鼠标跟随特效示例【2则实例】

    这篇文章主要介绍了JavaScript实现的鼠标跟随特效,结合2则实例形式分析了javascript针对鼠标事件的响应、计算、处理及页面元素动态操作相关实现技巧,需要的朋友可以参考下
    2018-12-12
  • vue3中Element Plus全局组件配置中文的两种方案

    vue3中Element Plus全局组件配置中文的两种方案

    element-plus组件文字语言默认是英文,需要手动更改一下中文包 ,本文主要介绍了vue3中Element Plus全局组件配置中文的两种方案,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12

最新评论