[2020-06-11] dev, javascript, es2021

(Ad, please don’t block)

The ECMAScript proposal “Logical assignment operators” (by Justin Ridgewell and Hemanth HM) introduces the following compound assignment operators:

`a ||= b`

`a &&= b`

`a ??= b`

JavaScript already has the following compound assignment operators:

- Arithmetic assignment operators:
`+= -= *= /= %= **=`

- Bitwise assignment operators:
`&= ^= |=`

- Bitwise shift assignment operators:
`<<= >>= >>>=`

Each of these assignment operators works as follows:

- The expression:
`a op= b`

- is equivalent to:
`a = a op b`

Before we can examine the proposed operators, we have to take a brief detour and learn about *short-circuiting*.

The logical operator `||`

, `&&`

, `??`

all *short-circuit* – their second operands are only evaluated if their first operands don’t already determine the result:

Operator | Equivalent to |
---|---|

`a ¦¦ b` |
`a ? a : b` |

`a && b` |
`!a ? a : b` |

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

Logical assignment operators work differently from other compound assignment operators:

Assignment operator | Equivalent to | Only assigns if `a` is |
---|---|---|

`a ¦¦= b` |
`a ¦¦ (a = b)` |
Falsy |

`a &&= b` |
`a && (a = b)` |
Truthy |

`a ??= b` |
`a ?? (a = b)` |
Nullish |

Why is `a ||= b`

equivalent to the following expression?

`a || (a = b)`

Why not to this expression?

`a = a || b`

The former expression has the benefit of short-circuiting: The assignment is only evaluated if `a`

evaluates to `false`

. Therefore, the assignment is only performed if it’s necessary. In contrast, the latter expression always performs an assignment.

`??=`

to add missing properties ```
const books = [
{
isbn: '123',
},
{
title: 'ECMAScript Language Specification',
isbn: '456',
},
];
// Add property .title where it’s missing
for (const book of books) {
book.title ??= '(Untitled)';
}
assert.deepEqual(
books,
[
{
isbn: '123',
title: '(Untitled)',
},
{
title: 'ECMAScript Language Specification',
isbn: '456',
},
]);
```

Consider the following function which returns an expression spread out across multiple lines:

```
function canContainNumber(value) {
return typeof value === 'number'
|| typeof value === 'bigint'
|| typeof value === 'string'
;
}
assert.equal(canContainNumber(''), true);
assert.equal(canContainNumber(Symbol()), false);
```

This expression can be broken up as follows:

```
function canContainNumber(value) {
let result = false;
result ||= typeof value === 'number';
result ||= typeof value === 'bigint';
result ||= typeof value === 'string';
return result;
}
```

Note: There are other, probably better, ways to improve the initial code. E.g., a `switch`

statement.