What are the logical assignment operators ||=, &&= and ??= in Javascript?

Asked

Viewed 469 times

11

I recently came across a code snippet like the one shown below:

let alias = req.body.alias;
alias = (alias ||= alias = 'generic');

I’ve never seen that operator before ||=, but after a brief search, I discovered the existence of three of the same kind:

  • ||=
  • &&=
  • ??=

Since I’ve never seen them before, I had a few questions:

  1. What are these operators?
  2. Do they have a name? Which one?
  3. What are they for?
  4. Although I can run on the console of browser, when trying to run the same code above with Typescript in version 3.9.5, a syntax error is released. From which version do they appear in Ecmascript (Javascript)? And in Typescript?
  • 2

    I was in doubt because of that expression alias = (alias ||= alias = 'generic'); for me would be right alias ||= 'generic'; which is the semantic equivalent of alias = alias || 'generic';. Here is the definition of that operator and others of a similar nature.

  • 1

    Thanks @Augustovasques, your link has cleared it all up. A feature of a newer version of TS.

  • 2

    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.

  • PS: In your case this line is very tricky... probably it is very wrong..

2 answers

13


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 will say that I did not expect this to work in the snippet. In which edition of Ecmascript this proposal entered / will enter?

  • 4

    If I’m not mistaken you will enter ES2021 (not officially out yet), but Chrome (V8, in this sense) is well anticipated and already implements the Features before being ratified by the specification. As the proposal is already in Stage 4, it is certain that it will enter the language.

8

This is the operator composed of OR. That is, it is the || which already knows and works exactly the same, but it does an extra operation, it stores the result in the variable itself used, so it is an OR and an assignment.

x ||= y;

is the same as

x = x || y;

Assuming x and y fit into the context.

It now exists in version 4 of Typescript, so it must be using an old version. It looks like you need to update your TS. Must enter Ecmascript 2021.

It may be that I do not know something, but the code is very strange, I do not know if it is due to some legacy Javascript flaw (or some madness required by Node - it is not to happen, but these technologies surprise me), I understand that this code is the same as:

let alias = null;
alias ||= 'generic';
console.log(alias);

I put the null just to simplify, because the purpose of the original code is precisely to make the null turn a text, or not if a valid object exists.

Think about it, how crazy it is to keep a text in alias then apply an OR and save the result to itself and then take that result and store it in the same variable again?

If you’ve seen it in any project, run away from it.

  • Very well explained, now it worked after I updated the TS. Basically the same idea of mathematical operators, += for example, but the way you wrote it is much easier to understand than the code I saw. I don’t understand why create a resource x ||= y; just to simplify something simple x = x || y;. The guy who proposes this idea was in charge of typing an extra character? I don’t know.

  • 2

    In short, it’s like a += only instead of + is with ||. And with string I believe that Typescript recommends to use only if it is an empty string, if it is nullable is able to recommend the ??=. Here are other similar operators introduced in version 4.0

  • 3

    In the past the compound operator was faster. But this changed over time and the compiler went on to optimize. In scripting languages it doesn’t even matter that. But the pattern of programming has stayed that way. I like it, and it’s not because I type less, it’s because it shows more clearly, in my opinion, there are people who disagree, who are creating a side effect on the variable from itself. Those who disagree because they understand I even accept, those who disagree because they do not understand the reason, I tell them to pick up on the side of the road. I think the ??.In some languages the || nor works p/ this

Browser other questions tagged

You are not signed in. Login or sign up in order to post.