ES新提案:雙問號操作符

摘要: 簡單實(shí)用的新特性。

本文主要講Gabriel Isenberg撰寫的ES提案“Nullish coalescing for JavaScript”。 它提出?? 替換||的運(yùn)算符,并提供默認(rèn)值。這里先把這相提案叫作雙問號操作符,如果你有好的叫法,歡迎留言討論。

1. 概述

雙問號 ?? 的操作符跟 || 類似,如果給定變量值為 null 或者 undefined,剛使用雙問號后的默認(rèn)值,否則使用該變量值。

如下:

    > undefined ?? 'default'
    'default'
    > null ?? 'default'
    'default'
    > false ?? 'default'
    false
    > '' ?? 'default'
    ''
    > 0 ?? 'default'
    0

2. 早期的 || 運(yùn)算符號

直接來個例子來演示一下 || 運(yùn)算,下面兩個等式是等價的:

    a || b
    a ? a : b

如果 a 是 truthy 值,則返回 a, 否則返回 b。

這使得使用||指定一個默認(rèn)值成為可能,如果實(shí)際值是假的,那么將使用這個默認(rèn)值:

    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)']);

請注意,基本只有在實(shí)際值undefined或?yàn)?code>null時才應(yīng)使用默認(rèn)值,這是有效的,因?yàn)?code>undefined和null都是假(虛值)的:

    > undefined || 'default'
    'default'
    > null || 'default'
    'default'

遺憾的是,如果實(shí)際值是其他的虛值,也會使用默認(rèn)值:

    > false || 'default'
    'default'
    > '' || 'default'
    'default'
    > 0 || 'default'
    'default'

因此,這個getTitle()并不總能正常工作:

    assert.equal(
      getTitle({path: 'empty.html', title: ''}),
      '(Untitled)');

3. 使用雙問號操作符來解決 || 運(yùn)算的問題

?? 主要是用來解決 || 操作符號的一些問題,以下兩個表達(dá)式是等價的:

    a ?? b
    a !== undefined && a !== null ? a : b

默認(rèn)值是這樣提供的:

    const result = actualValue ?? defaultValue;

對于undefinednull, ??操作符的工作原理與||操作符相同

    > undefined ?? 'default'
    'default'
    > null ?? 'default'
    'default'

除了 undefinednull的其它虛值,?? 不會返回默認(rèn)值。

    > false ?? 'default'
    false
    > '' ?? 'default'
    ''
    > 0 ?? 'default'
    0

使用 ?? 來重寫 getTitle():

    function getTitle(fileDesc) {
      return fileDesc.title ?? '(Untitled)';
    }

現(xiàn)在使用fileDesc調(diào)用它,它的.title是空字符串,仍然可以按符合咱們的預(yù)期工作:

    assert.equal(
      getTitle({path: 'empty.html', title: ''}),
      '');

3.1 通過解構(gòu)給定默認(rèn)值

除了使用 ??getTitle添加默認(rèn)值,咱們也可以通過解構(gòu)方式來給定默認(rèn)值:

    function getTitle({title = '(Untitled)'}) {
      return title;
    }

3.2 使用 ?? 操作符號的實(shí)際例子

作為一個現(xiàn)實(shí)的例子,咱們使用??來簡化下面的函數(shù)。

    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 雙問號(??)操作符與可選鏈(?)

雙問號(??)的提出是為了補(bǔ)充可選鏈(?),來看看這兩兄弟結(jié)合使用的場景(第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沒法實(shí)時知道,事后為了解決這些BUG,花了大量的時間進(jìn)行l(wèi)og 調(diào)試,這邊順便給大家推薦一個好用的BUG監(jiān)控工具 Fundebug。

關(guān)于Fundebug

Fundebug專注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java線上應(yīng)用實(shí)時BUG監(jiān)控。 自從2016年雙十一正式上線,F(xiàn)undebug累計處理了20億+錯誤事件,付費(fèi)客戶有陽光保險、核桃編程、荔枝FM、掌門1對1、微脈、青團(tuán)社等眾多品牌企業(yè)。歡迎大家免費(fèi)試用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容