ES新提案:双问号操做符

做者:前端小智html

译者:Dr. Axel Rauschmayer前端

来源:2alitygit


阿里云最近在作活动,低至2折,有兴趣能够看看promotion.aliyun.com/ntms/yunpar…github


为了保证的可读性,本文采用意译而非直译。express

本文主要讲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, 不然返回 bspa

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

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

交流(欢迎加入群,群工做日都会发红包,互动讨论技术)

干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。

github.com/qq449245884…

我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,便可看到福利,你懂的。

相关文章
相关标签/搜索