摘要: 简单实用的新特性。

本文主要讲Gabriel Isenberg撰写的ES提案“Nullish coalescing for JavaScript”。 它提出?? 替换||的运算符,并提供默认值。这里先把这相提案叫作双问号操作符,如果你有好的叫法,欢迎留言讨论。

1. 概述

双问号 ?? 的操作符跟 || 类似,如果给定变量值为 null 或者 undefined,刚使用双问号后的默认值,否则使用该变量值。

如下:

    > undefined ?? 'default'
'default'
> null ?? 'default'
'default'
> false ?? 'default'
false
> '' ?? 'default'
''
> 0 ?? 'default'
0

2. 早期的 || 运算符号

直接来个例子来演示一下 || 运算,下面两个等式是等价的:

    a || b
a ? a : b

如果 a 是 truthy 值,则返回 a, 否则返回 b

这使得使用||指定一个默认值成为可能,如果实际值是假的,那么将使用这个默认值:

    const result = actualValue || defaultValue;
function getTitle(fileDesc) {
return fileDesc.title || '(Untitled)';
}
const files = [
{path: 'index.html', title: 'Home'},
{path: 'tmp.html'},
];
assert.deepEqual(
files.map(f => getTitle(f)),
['Home', '(Untitled)']);

请注意,基本只有在实际值undefined或为null时才应使用默认值,这是有效的,因为undefinednull都是假(虚值)的:

    > undefined || 'default'
'default'
> null || 'default'
'default'

遗憾的是,如果实际值是其他的虚值,也会使用默认值:

    > false || 'default'
'default'
> '' || 'default'
'default'
> 0 || 'default'
'default'

因此,这个getTitle()并不总能正常工作:

    assert.equal(
getTitle({path: 'empty.html', title: ''}),
'(Untitled)');

3. 使用双问号操作符来解决 || 运算的问题

?? 主要是用来解决 || 操作符号的一些问题,以下两个表达式是等价的:

    a ?? b
a !== undefined && a !== null ? a : b

默认值是这样提供的:

    const result = actualValue ?? defaultValue;

对于undefinednull??操作符的工作原理与||操作符相同

    > undefined ?? 'default'
'default'
> null ?? 'default'
'default'

除了 undefinednull的其它虚值,?? 不会返回默认值。

    > false ?? 'default'
false
> '' ?? 'default'
''
> 0 ?? 'default'
0

使用 ?? 来重写 getTitle():

    function getTitle(fileDesc) {
return fileDesc.title ?? '(Untitled)';
}

现在使用fileDesc调用它,它的.title是空字符串,仍然可以按符合咱们的预期工作:

    assert.equal(
getTitle({path: 'empty.html', title: ''}),
'');

3.1 通过解构给定默认值

除了使用 ??getTitle添加默认值,咱们也可以通过解构方式来给定默认值:

    function getTitle({title = '(Untitled)'}) {
return title;
}

3.2 使用 ?? 操作符号的实际例子

作为一个现实的例子,咱们使用??来简化下面的函数。

    function countMatches(regex, str) {
if (!regex.global) {
throw new Error('Regular expression must have flag /g: ' + regex);
}
const matchResult = str.match(regex); // null or Array
if (matchResult === null) {
return 0;
} else {
return matchResult.length;
}
} assert.equal(
countMatches(/a/g, 'ababa'), 3);
assert.equal(
countMatches(/b/g, 'ababa'), 2);
assert.equal(
countMatches(/x/g, 'ababa'), 0); // Flag /g is missing
assert.throws(
() => countMatches(/a/, 'ababa'), Error);

使用 ?? 操作符号后,简化如下:

    function countMatches(regex, str) {
if (!regex.global) {
throw new Error('Regular expression must have flag /g: ' + regex);
}
return (str.match(regex) ?? []).length;
}

3.3 双问号(??)操作符与可选链(?)

双问号(??)的提出是为了补充可选链(?),来看看这两兄弟结合使用的场景(第A行):

    const persons = [
{
surname: 'Zoe',
address: {
street: {
name: 'Sesame Street',
number: '123',
},
},
},
{
surname: 'Mariner',
},
{
surname: 'Carmen',
address: {
},
},
]; const streetNames = persons.map(
p => p.address?.street?.name ?? '(no name)'); // (A)
assert.deepEqual(
streetNames, ['Sesame Street', '(no name)', '(no name)']
);

4. 兼容性

可以通过ECMAScript Next compatibility table 查看 ?? 支持情况。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了20亿+错误事件,付费客户有阳光保险、核桃编程、荔枝FM、掌门1对1、微脉、青团社等众多品牌企业。欢迎大家免费试用

ES新提案:双问号操作符的更多相关文章

  1. C#中双问号、双冒号等几个特殊关键字

    1.@ 这个东东看似和邮件有关啊,但是在C#的世界里,可跟邮件没有一毛钱关系,它是string的女朋友(当然了string有N多女友),二者结合就可以发挥作用了.你可以给它起个名字,叫做“逐字字符串” ...

  2. C#中单问号,双问号的用法(转)

    原文:http://hi.baidu.com/guodong828/blog/item/c78fc23f847314cb7d1e7193.html 单问号---用于给变量设初值的时候,给变量(int类 ...

  3. php两个问号??表示什么意思,PHP两个问号运算符,双问号表达式

    有同学给子恒老师留言, 说在php源代码中看到有两个问号?? 不知道是什么意思. 其实两个问题??是php7新推出的表达式, c = a ?? b; 表示如果a非空,则c = a, 如果a为空,则 c ...

  4. Java 8 Lambda表达式之方法引用 ::双冒号操作符

    双冒号运算符就是java中的方法引用,方法引用的格式是类名::方法名. 这里只是方法名,方法名的后面没有括号“()”.--------> 这样的式子并不代表一定会调用这个方法.这种式子一般是用作 ...

  5. c#的问号?和双问号??

    1.问号?表示该变量可以为空 int? a=new int?(); Console.Writeline(a);//a是null 等价于: int? a=null; 也等价于下面这行,表示该变量默认为n ...

  6. C#单问号(?)与双问号(??)

    1.单问号(?) 1.1 单问号运算符可以表示:可为Null类型,C#2.0里面实现了Nullable数据类型 //A.比如下面一句,直接定义int为null是错误的,错误提示为无法将null转化成i ...

  7. java :: Java中的双冒号操作符

    java中的双冒号操作符 定义 双冒号运算操作符是类方法的句柄,lambda表达式的一种简写,这种简写的学名叫eta-conversion或者叫η-conversion. 通常的情况下: 把 x -& ...

  8. 蒲公英 · JELLY技术周刊 Vol.30: 此路不通?Vue 3 新提案 Ref-sugar

    蒲公英 · JELLY技术周刊 Vol.30 随着 Vue 3 发布,相关的新闻也逐渐火热起来,而近期 RFC 中两个新的提案也因为某乎上的一些事情变得广为人关注.Ref sugar和script s ...

  9. C#中单问号(?)和双问号(??)的用法整理

    1.单问号(?) 1.1 表示Nullable类型 C#2.0里面实现了Nullable数据类型 //A.比如下面一句,直接定义int为null是错误的,错误提示为无法将null转化成int,因为后者 ...

随机推荐

  1. GO基础之结构体

    1 .什么是结构体 GO语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型.结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 2.什么是实例化? Go结构体的 ...

  2. URL.createObjectURL()的使用方法

    URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL.这个 URL 的生命周期和创建它的窗口中的 document 绑定.这个新 ...

  3. fluwx使用的问题

    今天搞了下fluwx这个库,也是遇到了很多问题. 问题一:‘包名不对,请检查包名是否与开放平台上填写的一致’ 显示把文档这些看了遍,但是也不是很清楚,还加了下群问别人,主要我没有开发过Android, ...

  4. MySQL的高级应用之Explain(完美详细版,看这一篇就够了)

    原文链接: https://blog.csdn.net/wx1528159409/article/details/83819985

  5. 1. Linux-3.14.12内存管理笔记【系统启动阶段的memblock算法(1)】

    memblock算法是linux内核初始化阶段的一个内存分配器(它取代了原来的bootmem算法),实现较为简单.负责page allocator初始化之前的内存管理和分配请求. 分析memblock ...

  6. MYSQL的基本使用,以及错误代码的意思

    创建数据库: 要创建声明类型的数据库,输入CREATE DATABASE 数据库名称; 注意:命令不必以大写字母输入. 注意:所有MySQL命令必须以";"结束.如果忘记了输入分号 ...

  7. LRU的实现(使用list)

    首先是LRU的定义,LRU表示最近最少使用,如果数据最近被访问过,那么将来被访问的几率也更高. 所以逻辑应该是每次都要将新被访问的页放到列表头部,如果超过了list长度限制,就将列表尾部的元素踢出去. ...

  8. OSPF与ACL综合实验

    OSPF与ACL综合实验 1.实验内容 (1)企业内网运行OSPF路由协议,区域规划如拓扑图所示(见3.实验拓扑图): (2)财务和研发所在的区域不受其他区域链路不稳定性影响: (3)R1.R2.R3 ...

  9. 使用python对整个网页进行截图

    方法一.使用PyQt4的QtWebKit组件 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ...

  10. JVM-0-JVM知识体系