ES New Proposal: Double Question Mark Operator

Posted by en on Tue, 27 Aug 2019 02:08:43 +0200

To ensure readability, this paper uses free translation instead of literal translation.

To read more high-quality articles, stamp the GitHub blog, and over a hundred high-quality articles are waiting for you a year!

This week, Daqian World has a draw with prizes: column "Hearing the Wind in the Left Ear" x3, technical book x5. Welcome to Reply: Draw Prizes

This article focuses on the ES proposal by Gabriel Isenberg "Nullish coalescing for JavaScript" .It suggests?? Replace the || operator and provide default values.Call this proposal a double question mark operator first. If you have a good name, you are welcome to leave a message for discussion.

1. Overview

The double question mark?? operator is similar to ||, if a given variable value is null or undefined, the default value just after the double question mark is used, otherwise the variable value is used.

The following:

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

2. Early || Operational Symbols

To illustrate the || operation directly, the following two equations are equivalent:

a || b
a ? a : b

If A is a true value, A is returned, otherwise b is returned.

This makes it possible to specify a default value using |, which will be used if the actual value is false:

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

Note that the default value should be used basically only if the actual value undefined or null, which is valid because both undefined and null are false:

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

Unfortunately, if the actual value is another virtual value, the default value is also used:

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

Therefore, this getTitle() does not always work:

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

3. Use the double question mark operator to solve the problem of the || operation

?? Is mainly used to solve some problems with || operation symbols. The following two expressions are equivalent:

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

The default value is provided as follows:

const result = actualValue ?? defaultValue;

For undefined and null, the?? operator works the same way as the || operator

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

Does not return the default value except undefined and null.

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

Use?? to override getTitle():

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

Now call it with fileDesc, its.title is an empty string, and it will still work as expected:

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

3.1 Default values given by deconstruction

In addition to using?? to add default values to getTitle, we can also deconstruct the default values:

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

3.2 Use?? Practical examples of manipulating symbols

As a practical example, let's use?? to simplify the following functions.

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

With?? symbols, simplify as follows:

function countMatches(regex, str) {
  if (!regex.global) {
    throw new Error('Regular expression must have flag /g: ' + regex);
  }
  return (str.match(regex) ?? []).length;
}

3.3 Double question mark (??) operator and optional chain (?)

The double question mark (??) was proposed to complement the optional chain (?) to see what the two brothers were doing together (line 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)']
);

BUGs that may exist after code deployment are not known in real time. In order to solve these BUGs afterwards, a lot of time has been spent debugging the log. By the way, a useful BUG monitoring tool is recommended. Fundebug.

4. Compatibility

By ECMAScript Next compatibility table View?? Support.

Communication

The dry goods series articles are summarized below, feel good to order Star, welcome to join the group to learn from each other.

https://github.com/qq44924588...

I am Xiao Zhi, the author of the public number "Move the World", a fan of keeping learning about front-end technology.I often share what I've learned and what I've seen. On the way to the next level, I'll reluctantly!

Focus on the public number and reply to the benefits in the background. You can see the benefits, you know.

Topics: Javascript github ECMAScript