当前位置: 移动技术网 > IT编程>开发语言>JavaScript > ES新提案:双问号操作符

ES新提案:双问号操作符

2019年08月28日  | 移动技术网IT编程  | 我要评论

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

本文主要讲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: '', 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. 兼容性

可以通过 查看 ?? 支持情况。

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

关于fundebug

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网