Trimming JavaScript: ditch verbosity, gain readability

RMAG news

Are you familiar with expressions like these:

a !== undefined && a !== null ? a : b
if (a.x === undefined || a.x === null) { a.x = b }
{ foo: foo, bar: bar }
a ? a.b : undefined
function getX(o) { return o.x }

What do they all have in common? They are highly verbose, and all have a nice shorthand alternatives. Let’s see how we can improve each one of these:

Nullish coalescing operator ??

This operator checks the value of the left hand-side operand – if it’s null or undefined, it returns the right hand-side operand. Otherwise it returns the left hand-side, without evaluating the right hand-side.
This allows simplifying the following expression:

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

To this:

a ?? b

Unlike || operator that checks for any falsy value, this operator only checks for nullish values – meaning null or undefined. Therefore it is safer to use in cases that a is a boolean which can be false or a number which can be 0, and then a || b will return the value of b

Nullish coalescing assignment ??=

This operator only evaluates the right operand and assigns to the left if the left operand is null or undefined.
So we can simplify this expression:

if (a.x === undefined || a.x === null) {
a.x = b
}

to this:

a.x ??= b

JSON shorthand syntax

The shorthand syntax was introduced with ES6 and is already pretty common.
Use it to shorten this:

const name = john doe
const age = 32
const talk = text => void console.log(text)
const person = {
name: name,
age: age,
talk: talk
}

to that:

const name = john doe
const age = 32
const talk = text => void console.log(text)
const person = {
name,
age,
talk
}

Optional chaining ?.

This operator accesses an object’s property just like . does. However, unlike ., if the object is null or undefined, the expression will return undefined instead of throwing an error.
This allows replacing this code:

a ? a.b : undefined

with that:

a?.b

This operator is pretty strong, and can be used in various ways:

Chaining: a?.b?.c?.d

Call interface method: someInterface.customMethod?.()
Note that in this case, if customMethod exists, but it is not a function, you’d still get an exception someInterface.customMethod is not a function

Access dynamic property with bracket notation: x?.[propname]

Access array items: array?.[50] – even if array is nullish, you’d get undefined instead of an exception

Arrow functions

There’s a lot to say about arrow functions, but in the context of this post I want to focus on a specific use – 1 liner methods that calculate something or access some property. They have 2 attributes that help with code shortening:

Arrow functions that do not have a block body wrapped with curly brackets {/*…*/} have an implicit return.
in a single-param arrow function you do not have to put the argument in parentheses
Meaning, you can change this:

function getX(o) {
return o.x
}

with this

const getX = o => o.x

This is super useful, for example, for mapping functions.
Note that there are some caveats though:

Arrow functions do not have this

Arrow functions do not have arguments. You can use spread operator instead. E.g (…args) => args[0]
Arrow functions cannot call super or be used as constructors

Leave a Reply

Your email address will not be published. Required fields are marked *