Optional Chaining & Nullish Coalescing

Reviewed & published by Brayan K

Optional chaining (?.) safely reads deeply nested values without crashing on missing data, and nullish coalescing (??) supplies a fallback only when a value is null or undefined.

Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Together they replace long a && a.b && a.b.c guards and buggy || defaults with two tiny, precise operators.

What You'll Learn in This Lesson

📚 Prerequisites: You should understand objects, arrays, and the idea of truthy and falsy values. These operators are all about handling null and undefined gracefully.

🔗 Real-World Analogy: Optional chaining is like a cautious tour guide:

1️⃣ Optional Chaining on Properties

Reading user.address.city throws if address is missing. Optional chaining fixes that: user.address?.city stops and returns undefined the moment a link in the chain is null or undefined. This short-circuiting is the whole point — it never even evaluates what comes after the missing piece.

Only place ?. where data might be missing. If you know user always exists, write user.address?.city — over-using ?. can hide real bugs.

const user = { name: "Ada", address: { city: "London" } };
const ghost = { name: "Nobody" }; // no address

console.log(user?.address?.city);   // ✅ Expected output: London
console.log(ghost?.address?.city);  // ✅ Expected output: undefined

// Without ?. the next line would throw — with it, it's safe
console.log(ghost.address?.city);   // ✅ Expected output: undefined

2️⃣ Optional Calls & Array Access

The same idea works for methods and array indexing. Use obj.method?.() to call a method only if it exists — perfect for optional callbacks. Use arr?.[i] to index only when the array is actually there. If the thing isn't callable or indexable, you get undefined rather than a crash.

Note the syntax: for calls and indexes the ?. comes before the parentheses or brackets — fn?.() and arr?.[0], not fn()?..

const config = {
  log: (msg) => "logged: " + msg,
};

// Method exists → it runs. Method missing → undefined, no crash.
console.log(config.log?.("hi"));    // ✅ Expected output: logged: hi
console.log(config.warn?.("oops")); // ✅ Expected output: undefined

const maybeList = null;
console.log(maybeList?.[0]);         // ✅ Expected output: undefined

const tags = ["js", "ts"];
console.log(tags?.[1]);              // ✅ Expected output: ts

3️⃣ Nullish Coalescing (??), ?? vs ||, and ??=

Optional chaining gives you undefined when data is missing — and ?? turns that into a sensible default. The crucial difference from ||: ?? only falls back for null and undefined, while || also falls back for 0, "", and false. That distinction prevents a very common bug. The ??= operator assigns a default only when the target is nullish.

Pairs beautifully: const city = user?.address?.city ?? "Unknown"; reads safely AND provides a clean default in a single, readable line.

const settings = { volume: 0, label: "" };

// || wrongly discards 0 and "" — ?? keeps them
console.log(settings.volume || 5);   // ✅ Expected output: 5   (wrong default!)
console.log(settings.volume ?? 5);   // ✅ Expected output: 0   (correct)
console.log(settings.label  ?? "n/a"); // ✅ Expected output: (empty string)

// Combine ?. with ??
const user = { profile: null };
console.log(user.profile?.name ?? "Guest"); // ✅ Expected output: Guest

// ??= sets a default only when nullish
const opts = { theme: undefined };
opts.theme ??= "dark";
console.log(opts.theme);             // ✅ Expected output: dark

🎯 Your Turn — Safe Read with a Default

Read city safely and fall back to "Unknown" if it's missing.

const user = { name: "Lee" }; // no address

// 👉 replace ___ : read address.city safely, default to "Unknown"
const city = user?.address?.___ ___ "Unknown";

console.log(city);
// ✅ Expected output: Unknown

🧠 Quick Recall

Predict the output before revealing the answer.

An empty string — ?? only replaces null/undefined, and "" is neither.

fallback — || falls back on any falsy value, and "" is falsy.

undefined — the chain short-circuits at the very first null.

Common Errors & Fixes

🎯 Mini Challenge — Robust Config Reader

Read deeply nested settings safely and apply sensible defaults that keep valid 0 values.

function readVolume(config) {
  // 👉 read audio.volume safely; default to 50 only if it is missing
  return config?.audio?.volume ?? 50;
}

console.log(readVolume({ audio: { volume: 0 } }));  // ✅ Expected output: 0
console.log(readVolume({ audio: {} }));             // ✅ Expected output: 50
console.log(readVolume(null));                      // ✅ Expected output: 50

Quick Reference

GoalSyntax
Safe propertya?.b?.c
Safe callfn?.()
Safe indexarr?.[0]
Nullish fallbackx ?? def
Nullish assignx ??= def

📚 Keep Learning

🎉 Lesson Complete — Optional Chaining & Nullish Coalescing!

Practice quiz

What does optional chaining (?.) return when a link in the chain is null or undefined?

  • null
  • An error is thrown
  • undefined
  • false

Answer: undefined. ?. short-circuits and evaluates to undefined instead of throwing a 'cannot read property' error.

Given ghost = { name: 'Nobody' } (no address), what does ghost?.address?.city return?

  • undefined
  • null
  • ''
  • It throws

Answer: undefined. The chain short-circuits at the missing address and returns undefined safely.

What is the difference between ?? and ||?

  • They are identical
  • || falls back only for null/undefined
  • ?? falls back for any falsy value
  • ?? falls back only for null/undefined; || falls back for any falsy value

Answer: ?? falls back only for null/undefined; || falls back for any falsy value. ?? only replaces null/undefined, while || also replaces 0, '', and false.

What does const count = 0; count ?? 10 evaluate to?

  • 10
  • 0
  • undefined
  • null

Answer: 0. 0 is not null or undefined, so ?? keeps it, giving 0 (unlike || which would give 10).

What does '' ?? 'fallback' evaluate to?

  • An empty string
  • 'fallback'
  • undefined
  • null

Answer: An empty string. ?? only replaces null/undefined; an empty string is neither, so it is kept.

What does '' || 'fallback' evaluate to?

  • An empty string
  • undefined
  • 'fallback'
  • false

Answer: 'fallback'. || falls back on any falsy value, and '' is falsy, so it returns 'fallback'.

How do you safely call a method only if it exists?

  • obj.method()?.
  • obj.method?.()
  • obj?.method()
  • obj.method!.()

Answer: obj.method?.(). For optional calls, ?. comes before the parentheses: obj.method?.().

What does ??= do?

  • Always reassigns the variable
  • Compares two values
  • Deletes the property
  • Assigns the value only if the target is currently null or undefined

Answer: Assigns the value only if the target is currently null or undefined. Nullish assignment x ??= y sets y only when x is null or undefined.

What is the result of const o = null; o?.x?.y?

  • null
  • undefined
  • An error
  • 0

Answer: undefined. The chain short-circuits at the very first null and returns undefined.

Why can a?.b.c still throw even though it uses optional chaining?

  • ?. doesn't work on objects
  • It never throws
  • If a.b is missing, the non-optional .c still throws — guard every link with a?.b?.c
  • c must be a function

Answer: If a.b is missing, the non-optional .c still throws — guard every link with a?.b?.c. ?. only guards the link it is attached to; you must write a?.b?.c to guard every possibly-missing link.

Continue this course

Frequently asked questions

What exactly does optional chaining (?.) do?

It reads a property, calls a method, or indexes an array only if the value to its left is not null or undefined. If that value IS null or undefined, the whole expression short-circuits and evaluates to undefined instead of throwing a 'cannot read property of undefined' error.

What is the difference between ?? and ||?

The OR operator || falls back whenever the left side is falsy — that includes 0, empty string, and false. The nullish coalescing operator ?? only falls back when the left side is null or undefined. Use ?? when 0, '', and false are valid values you want to keep.

What does ??= do?

It is nullish assignment. x ??= y assigns y to x only if x is currently null or undefined. It is a concise way to set a default on a variable or property without overwriting an existing meaningful value like 0 or an empty string.

Can I use optional chaining for function calls and array access?

Yes. obj.method?.() calls method only if it exists, and arr?.[0] indexes only if arr is not null/undefined. This is great for optional callbacks and data that may or may not be an array.

Related lessons