Optional Chaining and ??

JavaScript ES2024 · ✓ verified by execution on 2026-08-15

When working with nested data, you often need to access a property deep inside an object. But if any part of that path is missing, your code will crash with the dreaded Cannot read properties of undefined error.

The optional chaining operator (?.) prevents this by stopping the access if it encounters null or undefined.

Safe Property Access

If you try to read a property from null, JavaScript throws an error. With ?., it simply returns undefined.

javascript
const user = null;
console.log(user?.name);
Output
undefined

This is especially powerful when navigating nested objects. You don’t need to write long if statements to check if user exists and if user.profile exists before reading age.

javascript · visualize
const user = { details: { name: 'Alice' } };
console.log(user.profile?.age);

As you step through the code above, notice how execution stops right at the ?. when user.profile evaluates to undefined.


user .profile .age ?. ?. short-circuits to undefined undefined
Optional chaining short-circuits the evaluation and returns undefined immediately.

Arrays and Functions

You can also use the optional chaining operator with bracket notation to safely access array elements. The ?. comes right before the bracket.

javascript
const users = ['Alice', 'Bob'];
console.log(users?.[0]);
console.log(users?.[5]);
Output
Alice
undefined

It even works with function calls. You can use optional chaining when attempting to call a method which may not exist. If the method is absent, it safely returns undefined instead of throwing an error.

javascript
const user = { sayHi() { console.log('Hi'); } };
user.sayHi?.();
user.sayBye?.();
Output
Hi

The Nullish Coalescing Operator (??)

When optional chaining returns undefined, you often want to provide a fallback value. The nullish coalescing operator (??) returns its right-hand side operand when its left-hand side operand is null or undefined.

javascript
const score = null;
console.log(score ?? 10);
Output
10

This pairs perfectly with optional chaining:

javascript
const data = null;
console.log(data?.items ?? 'No items');
Output
No items

Common Misconceptions: || vs ??

You might be used to using the logical OR operator (||) to provide default values. But there is a critical difference: || falls back if the value is any falsy value, like 0 or an empty string "".

Nullish coalescing (??) only falls back for null or undefined.

Predict the output javascript

Read the code. What exactly will it print? Commit to an answer before you look.

const config = { retries: 0 };
console.log(config.retries ?? 3);
console.log(config.retries || 3);
Output
0
3

In the example above, 0 is a valid number of retries. The ?? operator respects the 0, while the || operator treats it as falsy and overwrites it with 3.

Check yourself

What does the optional chaining operator (?.) return if the property doesn't exist?

Reveal answer

It returns undefined — Optional chaining short-circuits and returns undefined. It never returns null, even if the object itself was null.

Is the nullish coalescing operator (??) exactly the same as logical OR (||)?

Reveal answer

No, || falls back on any falsy value, while ?? only falls back on null or undefined — Logical OR (||) treats 0 and an empty string as falsy, triggering the fallback. Nullish coalescing (??) correctly treats 0 and empty strings as valid values, only falling back for null or undefined.

Do you need to use ?. on every single property in a long chain just to be safe?

Reveal answer

No, you only need ?. at the exact point where a value might be null or undefined — You only need ?. at the point where a value might be nullish. If it short-circuits, the rest of the chain will not execute, so subsequent dots do not need it unless they independently might be nullish.

Can you use optional chaining to assign a value, like user?.name = "Alice"?

Reveal answer

No, it causes a SyntaxError — Optional chaining is strictly for reading values or calling functions. It causes a SyntaxError if used on the left side of an assignment.

Challenges

Challenge 1 +10 XP

Write a function `getCity(user)` that safely returns the user's `address.city` using optional chaining, or `"Unknown"` using nullish coalescing if any part of the address is missing.

javascript
  • Test 1 (input: "{\"address\": {\"city\": \"Tokyo\"}}") — expects "Tokyo"
  • Test 2 (input: "null") — expects "Unknown"
Need a hint? (−25% XP)

Chain `user?.address?.city` and use `??` for the fallback.

Show solution (0 XP)
import fs from 'node:fs';
const user = JSON.parse(fs.readFileSync(0, 'utf-8'));

function getCity(user) {
  return user?.address?.city ?? "Unknown";
}

console.log(getCity(user));

🐞 Bug Hunt +15 XP

This configuration loader uses `||` to provide a default volume. But when a user tries to mute the sound by passing `0`, the game blares at full volume `100`! Fix the bug.

This code runs. It just does the wrong thing. Read it, find the defect, fix it — the tests below decide when you are right.

javascript
  • Test 1 (input: "{\"volume\": 50}") — expects "50"
  • Test 2 (input: "{\"volume\": 0}") — expects "0"
  • Test 3 (input: "{}") — expects "100"
Need a hint? (−25% XP)

The `||` operator treats `0` as falsy. What operator only falls back for `null` or `undefined`?

Show solution (0 XP)
import fs from 'node:fs';
const config = JSON.parse(fs.readFileSync(0, 'utf-8'));

function getVolume(config) {
  return config.volume ?? 100;
}

console.log(getVolume(config));