JavaScript logical assignment operators deep dive

Logical assignment is the newest kid in the ES2020 block to come out of stage 4 proposal and it just got its first browser support with the Chrome 86 release.

This is a deep dive into what logical assignment is and how it works.

Logical assignment is an expansion on the existing mathematical and binary logical operators. Let’s review those first, and then we can look at what combining them together gains us.

First, let me explain the difference between conditional vs. unconditional operators in JavaScript.

Unconditional vs. conditional

Mathematical operators, e.g. + are unconditional

In const x = 1 + 2, no matter what, we always add the LHS to the RHS, and assign the result to x.

You can even write some strange code such as const x = false + 2. JavaScript first converts the LHS of false to a Number, so you get const x = Number(false) + 2 which evaluates to const x = 0 + 2, then it adds the LHS to the RHS, and finally assigns it to x, yielding 2.

The point to remember here is that the + and = operators are always evaluated.

Logical operators, e.g. && are conditional

In const x = true && 0 + 2, the LHS is evaluated first, which is true. Since the LHS evaluated to true, we next run the RHS operation, which evaluates to 2, and also run the assignment operation, yielding 2.

In contrast with const x = false && 0 + 2, the LHS is evaluated to false, so the RHS is completely ignored.

You might be wondering why you would want to avoid evaluating the RHS? The 2 common reasons are better performance and avoiding side effects.

Binary logical operators

&& || ??

You’re probably already using && and || in your JSX to conditionally render things. The ?? is the nullish coalescing operator which is slightly newer and will have its own blog post later. They are all binary logical operators.

It’s also helpful to visualize the behavior of the 3 different operators. Here’s a high level overview:

  • Use && to test the LHS for being truthy.
  • Use || to test the LHS for being falsey.
  • Use ?? to test the LHS for being nullish.

Falsey vs. Nullish

So what is considered falsey in JavaScript?

  • null
  • undefined
  • false
  • NaN
  • 0
  • "" e.g. empty string

And what is considered nullish?

  • null
  • undefined

It’s worth noting that with binary logical operators you don’t necessarily get a boolean back, but the value of either the LHS or RHS of the expression. In nailing home the point about these expression types, it’s helpful to reiterate this quote from the ECMAScript documentation:

The value produced by a && or || operator is not necessarily of type Boolean. The value produced will always be the value of one of the two operand expressions.

Some examples

// Binary logical operators
// &&
// If LHS is truthy, evaluate and return RHS, otherwise return LHS
true && 100 ** 2; // 10000
"Joe" && "JavaScript"; // "JavaScript"
false && 100 ** 2; // false
"" && 100 ** 2; // ""
NaN && 100 ** 2; // NaN
null && 100 ** 2; // null
undefined && 100 ** 2; // undefined

Introducing Logical Assignment operators

&&= ||= ??=

Now let’s introduce assignment into the mix.

This new operator combines assignment with the conditional logical operator, hence the name - logical assignment. You can think of them as shorthand. For example x &&= y is shorthand for x && (x = y). There are 3 logical assignment operators.

The value returned from logical assignments is not the updated assignment value, but the value of the evaluated expression.

Due to prior ECMAScript features like default parameters and the nullish coalescing operator, you could say that there’s definitely some redundancy in the functionality provided by logical assignments. Although the shorthand looks pretty slick and I’m sure it will come in handy as we find more use cases for it.

Logical AND Assignment

&&=

// Logical and
LHS &&= RHS;
// under the hood
LHS && (LHS = RHS);
// Example
// if x is truthy, assign x to y, otherwise return x
let x = 1;
const y = 100;
x &&= y; // x becomes 100
// Long version
x && (x = y);

Logical OR Assignment

||=

// Logical or
LHS ||= RHS;
// under the hood
LHS || (LHS = RHS);
// Example
// if x is truthy, return it, otherwise assign x to y
let x = NaN;
const y = 100;
x ||= y; // x becomes 100
// Long version
x || (x = y);

Logical NULLISH COALESCING Assignment

??=

// Logical nullish coalescing
LHS ??= RHS;
// under the hood
LHS ?? (LHS = RHS);
// Example
// if x.z is nullish, assign x.z to y
let x = {};
let y = 100;
x.z ??= y; // x becomes { z: 100 }
// Long version
x.z ?? (x.z = y);

Real world examples of logical assignment

Wrapping my head around new concepts always works better if I can relate it to a real world scenario. Here are some examples to help you understand usage of the logical assignment operator by seeing it in action.

JSX in React

// loading will become the spinner element
let loading = true;
const spinner = <Spinner />;
loading &&= spinner;

DOM

// innerHTML both sets and gets contents of an Element
// Don't want to set unless, innerHTML returns falsey
el.innerHTML ||= "some default";

Objects

// set the onLoad method on the config object if it doesn't exist
const config = {};
config.onLoad ??= () => console.log("loaded!");
const myObject = { a: {} };
myObject.a ||= "A"; // ignored since a exists on myObject
myObject.b ||= "B"; // myObject.b is created since its falsey
// myObject is now
// {
//  "a": {}
//  "b": "B"
// }
myObject.c &&= "Am I seen?"; // myObject.c is falsey so nothing happens

Start using logical assignment in your projects

Logical assignment is already supported in Google Chrome. To be backwards compatible, use a transformer. If you are using Babel, install the plugin…

npm install @babel/plugin-proposal-logical-assignment-operators

…and add it to your .babelrc plugins section.

{
  "plugins": ["@babel/plugin-proposal-logical-assignment-operators"]
}

Share your usage 💻

Logical assignment is super new so there isn’t much out there in the wild yet. If you have other examples of great uses for logical assignment please leave a comment below. I would love to see where others are using it.

References