摘要: 簡單實用的新特性。html
本文主要講Gabriel Isenberg撰寫的ES提案「Nullish coalescing for JavaScript」。 它提出??
替換||
的運算符,並提供默認值。這裏先把這相提案叫做雙問號操做符,若是你有好的叫法,歡迎留言討論。前端
雙問號 ??
的操做符跟 ||
相似,若是給定變量值爲 null
或者 undefined
,剛使用雙問號後的默認值,不然使用該變量值。git
以下:github
> undefined ?? 'default' 'default' > null ?? 'default' 'default' > false ?? 'default' false > '' ?? 'default' '' > 0 ?? 'default' 0
直接來個例子來演示一下 ||
運算,下面兩個等式是等價的:express
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
都是假(虛值)的:segmentfault
> undefined || 'default' 'default' > null || 'default' 'default'
遺憾的是,若是實際值是其餘的虛值,也會使用默認值:微信小程序
> false || 'default' 'default' > '' || 'default' 'default' > 0 || 'default' 'default'
所以,這個getTitle()
並不總能正常工做:微信
assert.equal( getTitle({path: 'empty.html', title: ''}), '(Untitled)');
??
主要是用來解決 ||
操做符號的一些問題,如下兩個表達式是等價的:
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: ''}), '');
除了使用 ??
給getTitle
添加默認值,我們也能夠經過解構方式來給定默認值:
function getTitle({title = '(Untitled)'}) { return title; }
做爲一個現實的例子,我們使用??
來簡化下面的函數。
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; }
雙問號(??
)的提出是爲了補充可選鏈(?
),來看看這兩兄弟結合使用的場景(第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)'] );
能夠經過ECMAScript Next compatibility table 查看 ??
支持狀況。
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
Fundebug專一於JavaScript、微信小程序、微信小遊戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了20億+錯誤事件,付費客戶有陽光保險、核桃編程、荔枝FM、掌門1對一、微脈、青團社等衆多品牌企業。歡迎你們免費試用!