摘要: 簡單實用的新特性。 原文: "ES新提案:雙問號操作符" 譯者:前端小智 本文主要講 Gabriel Isenberg 撰寫的ES提案[“Nullish coalescing for JavaScript”][2]。 它提出 替換 的運算符,並提供預設值。這裡先把這相提案叫作 雙問號操作符 ...
摘要: 簡單實用的新特性。
- 原文: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: {
},
},
];
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、微脈、青團社等眾多品牌企業。歡迎大家免費試用!