Are the logical allocation operators. In Javascript, they were standardized from Ecmascript 2021 based on the call Logical assignments Proposal.
These are the three new logical allocation operators:
Operator |
Name |
Equivalence ("old") |
Assigns only if |
a &&= b |
Logical allocation operator AND |
a && (a = b) |
a for Truthy |
a ||= b |
Logical allocation operator OR |
a || (a = b) |
a for falsy |
a ??= b |
Logical allocation operator nullish |
a ?? (a = b) |
a for nullish |
The logical functioning of such operators is the same as that of short-circuit operators &&
, ||
and ??
. The difference is that, depending on the result of this logical evaluation, they also perform variable assignment. Because of this dual functionality, they can also be called composite operators.
How evaluation occurs from left to right, a
will only receive the value of b
if, at the time of evaluation, the logical behaviour is favourable. Therefore, the operation [[Set]]
(carried out by the allocation operator =
) shall be executed only if the short-circuit permits.
It is also worth noting that any of the three operators of logical assignment will evaluate for the value of the variable referenced to the left, occurring attribution or not. This way, you can concatenate expressions that involve the use of these operators, always having the guarantee that the most recent value of the variable on the left will be returned by the expression.
Let’s see how logical behavior works for each of them...
Logical attribution AND (&&=
)
The logical allocation operator AND (&&=
) will execute the assignment if the left operand is Truthy, following the same operational logic as the &&
short-circuited.
If the value of the variable referenced on the left is falsy, nothing will occur. The value will be kept the same.
Thus:
// Exemplo de avaliação FAVORÁVEL.
// Neste caso, o operando à esquerda de `&&=` é truthy.
// A atribuição ocorrerá.
let x = 'Antigo X (que é truthy)';
x &&= 'Novo X';
console.log('x:', x); //=> "Novo X". Atribuiu porque `x` já era truthy.
// Exemplo de avaliação DESFAVORÁVEL.
// Neste caso, o operando à esquerda de `&&=` é falsy.
// A atribuição NÃO ocorrerá.
let y;
y &&= 'Novo Y';
console.log('y:', y); //=> undefined. NÃO ocorreu atribuição porque `y` já era falsy.
Logical assignment OR (||=
)
The logical allocation operator OR (||=
) will execute the assignment if the left operand is falsy, following the same operational logic as the ||
short-circuited.
If the value of the variable referenced on the left is Truthy, nothing will occur. The value will be kept the same.
Thus:
// Exemplo de avaliação FAVORÁVEL.
// Neste caso, o operando à esquerda de `||=` é falsy.
// A atribuição ocorrerá.
let x;
x ||= 'Novo X';
console.log('x:', x); //=> "Novo X". Atribuiu porque `x` já era falsy.
// Exemplo de avaliação DESFAVORÁVEL.
// Neste caso, o operando à esquerda de `||=` é truthy.
// A atribuição NÃO ocorrerá.
let y = 'Antigo Y (que é truthy)';
y ||= 'Novo Y';
console.log('y:', y); //=> "Antigo Y (que é truthy)". NÃO ocorreu atribuição porque `y` já era truthy.
Logical attribution nullish (??=
)
The logical allocation operator nullish (??=
) will execute the assignment if the left operand is nullish, following the same operational logic as the ??
short-circuited.
If the value of the variable referenced on the left is different from null
or undefined
(that is, a no value nullish), nothing will occur. The value will be kept the same.
Thus:
// Exemplo de avaliação FAVORÁVEL.
// Neste caso, o operando à esquerda de `??=` é nullish.
// A atribuição ocorrerá.
let x;
x ??= 'Novo X';
console.log('x:', x); //=> "Novo X". Atribuiu porque `x` já era nullish (nesse caso, `undefined`).
// Exemplo de avaliação DESFAVORÁVEL.
// Neste caso, o operando à esquerda de `??=` é não nullish (diferente de `null` ou diferente de `undefined`).
// A atribuição NÃO ocorrerá.
let y = 'Antigo Y (que é truthy)';
y ??= 'Novo Y';
console.log('y:', y); //=> "Antigo Y (que é truthy)". NÃO ocorreu atribuição porque `y` já era não nullish.
Concluding remarks
I’ll use the ||=
as an example, but applies to others as well.
Many people may think that a ||= b
is equivalent to this:
a = a || b;
However, this definition is not 100% accurate since, as we have seen, the logical assignment operators nay execute the [[Set]]
if the assessment of the corresponding logical operator is not favourable. In the example above, the allocation at all times will occur, so that a
will always be reallocated to the result of the expression a || b
, which in turn evaluates to b
if a
for falsy (following the example of ||=
and logical semantics of ||
).
Therefore, a more appropriate "equivalence" would be:
a || (a = b);
So that, only if a
for falsy, the expression shall be evaluated a = b
, which it will ultimately assign to a
the value of b
. The assignment only occurs if the logic of the ||
is favourable to short circuit.
And about the question code:
let alias = req.body.alias;
alias = (alias ||= alias = 'generic');
Doesn’t make much sense, since you’re attributing alias
twice if alias
for falsy. Or one, if req.body.alias
is already coming Truthy. Then something like this would be enough:
req.body.alias ||= 'generic';
// Utilize `alias` sabendo que sempre terá algum valor truthy.
console.log(req.body.alias);
So that the property alias
receive the value "Generic" if it is falsy. Maybe in that case it’s worth using the ??=
to assign only if alias
for nullish. But that’s only your business rule.
It is worth remembering, too, that it will only work if body
be present req
, but there already involves other semantics of language.
Although it is a feature of Javascript, Typescript now supports it from the version 4.0.
I was in doubt because of that expression
alias = (alias ||= alias = 'generic');
for me would be rightalias ||= 'generic';
which is the semantic equivalent ofalias = alias || 'generic';
. Here is the definition of that operator and others of a similar nature.– Augusto Vasques
Thanks @Augustovasques, your link has cleared it all up. A feature of a newer version of TS.
– Cmte Cardeal
Whenever I have doubts about these "groupings" of operations I always check the operator precedence table and then break the line into several separate operations to facilitate understanding. It’s a good tip for any language.
– fernandosavio
PS: In your case this line is very tricky... probably it is very wrong..
– fernandosavio