ES新提案:双问号操作符
![作者头像](https://ask.qcloudimg.com/avatar/2188212/gipjgkaj9k.jpg)
摘要: 简单实用的新特性。
- 原文: ES新提案:双问号操作符
- 译者:前端小智
本文主要讲
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
时才应使用默认值,这是有效的,因为
undefined
和
null
都是假(虚值)的:
> 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;
对于
undefined
和
null
,
??
操作符的工作原理与
||
操作符相同
> undefined ?? 'default'
'default'
> null ?? 'default'
'default'
除了
undefined
和
null
的其它虚值,
??
不会返回默认值。
> 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: {