Null-safe property access (and conditional assignment) in ES6/2015

Solution 1:

Update (2022-01-13): Seems people are still finding this, here's the current story:

  • Optional Chaining is in the specification now (ES2020) and supported by all modern browsers, more in the archived proposal: https://github.com/tc39/proposal-optional-chaining
  • babel-preset-env: If you need to support older environments that don't have it, this is probably what you want https://babeljs.io/docs/en/babel-preset-env
  • Babel v7 Plugin: https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining

Update (2017-08-01): If you want to use an official plugin, you can try the alpha build of Babel 7 with the new transform. Your mileage may vary

https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

Original:

A feature that accomplishes that is currently in stage 1: Optional Chaining.

https://github.com/tc39/proposal-optional-chaining

If you want to use it today, there is a Babel plugin that accomplishes that.

https://github.com/davidyaha/ecmascript-optionals-proposal

Solution 2:

It's not as nice as the ?. operator, but to achieve a similar result you could do:

user && user.address && user.address.postcode

Since null and undefined are both falsy values (see this reference), the property after the && operator is only accessed if the precedent it not null or undefined.

Alternatively, you could write a function like this:

function _try(func, fallbackValue) {
    try {
        var value = func();
        return (value === null || value === undefined) ? fallbackValue : value;
    } catch (e) {
        return fallbackValue;
    }
}

Usage:

_try(() => user.address.postcode) // return postcode or undefined 

Or, with a fallback value:

_try(() => user.address.postcode, "none") // return postcode or a custom string

Solution 3:

2020 Solution, ?. and ??

You can now directly use ?. (Optional Chaining) inline to safely test for existence. All modern browsers support it.

?? (Nullish Coalescing) can be used to set a default value if undefined or null.

aThing = possiblyNull ?? aThing
aThing = a?.b?.c ?? possiblyNullFallback ?? aThing

If a property exists, ?. proceeds to the next check, or returns the valid value. Any failure will immediately short-circuit and return undefined.

const example = {a: ["first", {b:3}, false]}

example?.a  // ["first", {b:3}, false]
example?.b  // undefined

example?.a?.[0]     // "first"
example?.a?.[1]?.a  // undefined
example?.a?.[1]?.b  // 3

domElement?.parentElement?.children?.[3]?.nextElementSibling

null?.()                // undefined
validFunction?.()       // result
(() => {return 1})?.()  // 1

To ensure a default defined value, you can use ??. If you require the first truthy value, you can use ||.

example?.c ?? "c"  // "c"
example?.c || "c"  // "c"

example?.a?.[2] ?? 2  // false
example?.a?.[2] || 2  // 2

If you do not check a case, the left-side property must exist. If not, it will throw an exception.

example?.First         // undefined
example?.First.Second  // Uncaught TypeError: Cannot read property 'Second' of undefined

?. Browser Support - 92%, Nov 2021

?? Browser Support - 92%

Mozilla Documentation

--

Logical nullish assignment, 2020+ solution

New operators are currently being added to the browsers, ??=, ||= and &&=. They don't do quite what you are looking for, but could lead to same result depending on the aim of your code.

NOTE: These are not common in public browser versions yet, but Babel should transpile well. Will update as availability changes.

??= checks if left side is undefined or null, short-circuiting if already defined. If not, the left side is assigned the right-side value. ||= and &&= are similar, but based on the || and && operators.

Basic Examples

let a          // undefined
let b = null
let c = false

a ??= true  // true
b ??= true  // true
c ??= true  // false

Object/Array Examples

let x = ["foo"]
let y = { foo: "fizz" }

x[0] ??= "bar"  // "foo"
x[1] ??= "bar"  // "bar"

y.foo ??= "buzz"  // "fizz"
y.bar ??= "buzz"  // "buzz"

x  // Array [ "foo", "bar" ]
y  // Object { foo: "fizz", bar: "buzz" }

Browser Support Nov 2021 - 90%

Mozilla Documentation