James Quigley's Blog

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, a DevOps Engineer, full-stack dev, and general tech nerd. Follow him on Twitter!