Black lives matter

# ECMAScript feature: Logical assignment operators

[2020-06-11] dev

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

• `a ||= b`
• `a &&= b`
• `a ??= b`

## Existing compound assignment operators  #

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`

## Recap: short circuiting  #

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`

## The proposed logical assignment operators  #

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.

## Example: using `??=` 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',
},
]);
``````

## Example: breaking up an expression  #

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.