Node 14 New JavaScript Feature Spotlight
April 27, 2020
Node.js version 14 was released recently, and will become active under Long Term Support (LTS) version in fall of 2020 (October 20th to be specific). There are a handful of changes, but to the average developer, I think a few are worth highlighting as they might change the JavaScript that gets read and written.
Nullish Coalescing
Nullish Coalescing is similar to the ||
operator, but it only returns the right hand value when the left hand side is nullish, instead of falsy.
/**
* Zero is considered falsy and therefore
* the right hand side value is returned
* when using the `||` operator
*/
const foo = 0 || "oops" // "oops"
const bar = null || "oops" // "oops"
/**
* Zero is not considered nullish
* and therefore is returned when on
* the left hand side of the `??` operator
*/
const baz = 0 ?? "oops" // 0
const buzz = null ?? "oops" // "oops"
Falsy
Falsy is a term that means a value that is considered to be false when treated as a boolean. In JavaScript, the following values are falsy:
null
undefined
NaN
(Not a number)0
-0
(yes that’s right, negative zero)0n
(BigInt zero)""
(the empty string)false
(You’d really hope)
These values being falsy can be simultaneously convenient, but also a pain if forgotten. It is common in JavaScript to pass a non-boolean value to an if
statement, and let JavaScript check if the value is truthy or falsy. But if you unintentionally pass in 0
or ""
, you might encounter unexpected behavior.
if (1) // true
if (0) // false
This is why passing unsanitized input directly to an if
to check for the presence of value is an issue
Nullish
Similar to falsy, there are multiple values that are considered nullish. These values are:
null
undefined
This means that these values are both nullish and falsy.
Optional Chaining
Optional Chaining is a new feature that allows you to reference a field nested within several objects, but without having to check that each object isn’t nullish.
Let’s take the following object as an example:
const users = {
Jack: {
phone: "(123) 456-7890",
address: {
street: "6732 Main St",
zip: "12345",
},
},
// Notice jill has no address
Jill: {
phone: "(349) 233-2348",
},
}
In the past, if we wanted to get the zip code, we would have done something like:
const jack = users.Jack
let zip = null
if (jack) {
const address = jack.address
if (address) {
zip = address.zip // "12345"
}
}
or
let zip = null
if (users.Jack && users.Jack.address) {
zip = users.Jack.address.zip // "12345"
}
or if you really want to do it in one line:
const zip = users.Jack && users.Jack.address && users.Jack.address.zip
All of these are valid, but pretty verbose. With optional chaining you can now do the same thing still in one line, and without the use of if
, &&
, and without repeating any fields:
const zip = users.Jack?.address?.zip // "12345"
?.
replaces plain old .
and short circuits if the value is nullish. In the above example, Jack has an address and a zip, but Jill doesn’t. To check for Jill’s zip code, its the same thing:
const zip = users.Jill?.address?.zip // undefined
If you tried this line without the ?.
operator, it would throw an error!
One of the great things about Optional Chaining is that it works with just about everything. Not just object properties, but also arrays and function calls too.
function asyncHelloCallback(name, callback) {
const helloString = `Hello, ${name}!`
setTimeout(() => {
console.log(helloString)
// If callback is undefined, there's no error
callback?.(helloString)
})
}
function getFifthElement(arr) {
// Doesn't throw an error if arr is undefined
return arr?.[4]
}
Combining Optional Chaining and Nullish Coalescing
Combined, these two features can be quite the powerhouse.
// Check for value and provide a default if Nullish
const middleName = users.Jack?.middleName ?? ""
const quantity = order.items?.[0].quantity ?? 3
/**
* Use multiple nullish coalescing and
* optional chaining operators to check
* several values before providing a default
*/
const userNames = [
{
name: {
first: "John",
middle: "B",
last: "Doe",
},
},
{
name: {
last: "Smith",
},
},
{
name: {
middle: "A",
},
},
{},
]
const defaultName = user =>
user?.name?.first ?? user?.name?.last ?? user?.name?.middle ?? "Unknown"
// [ 'John', 'Smith', 'A', 'Unknown' ]
const defaultNames = userNames.map(defaultName)
Written by James Quigley, an SRE/DevOps Engineer, and general tech nerd. Views and opinions are my own. Check out my YouTube Channel or follow me on Twitter!