🌱BeginnerModern JavaScript

Optional Chaining & Nullish Coalescing

The ?. and ?? operators safely navigate nested properties and provide fallback values.

Overview

Two modern JavaScript operators transform how you handle potentially missing or null values. **Optional chaining (`?.`)** lets you safely access nested object properties without throwing if an intermediate value is `null` or `undefined`. Instead of crashing with "Cannot read properties of undefined", it short-circuits and returns `undefined`. Works on property access (`a?.b`), method calls (`a?.method()`), and array access (`a?.[i]`). **Nullish coalescing (`??`)** returns the right-hand side only when the left is `null` or `undefined` not for all falsy values. This is a key difference from `||`: `0 ?? "default"` returns `0` (because 0 is not null/undefined), while `0 || "default"` returns `"default"` (because 0 is falsy). Use `??` when 0 or `""` are valid values. They compose beautifully: `user?.address?.city ?? "Unknown"`.

Key Points

  • •`obj?.prop` returns `undefined` (not an error) if `obj` is null/undefined
  • •`obj?.method()` calls the method only if obj is not null/undefined
  • •`arr?.[index]` safe index access; `fn?.(args)` safe function call
  • •`??` returns the right side only when left is `null` or `undefined`
  • •`||` returns the right side for ANY falsy value (0, "", false, null, undefined, NaN)
  • •`??=` (nullish assignment) assign only if the current value is null/undefined: `x ??= "default"`
  • •`||=` assign only if current value is falsy; `&&=` assign only if current value is truthy
  • •Chain them: `a?.b?.c?.d ?? "fallback"` returns "fallback" if any link is null/undefined

Examples

Optional chaining on nested objects

const user = {
  name: "Alice",
  address: {
    city: "London",
    postcode: "W1A 1AA"
  }
};

const userNoAddress = { name: "Bob" };

// Without ?. crashes if address is undefined
// console.log(userNoAddress.address.city);  // TypeError!

// With ?. safe navigation
console.log(user?.address?.city);           // "London"
console.log(userNoAddress?.address?.city);  // undefined (no crash)

// Method call
console.log(user?.address?.toUpperCase?.());   // undefined (no method)
console.log(user?.name?.toUpperCase());         // "ALICE"

// Array element
const data = { items: [10, 20, 30] };
console.log(data?.items?.[1]);              // 20
console.log(data?.missing?.[0]);            // undefined

Nullish coalescing vs logical OR

// ?? vs || the key difference
const count = 0;
const name = "";

console.log(count || "no count");   // "no count" (0 is falsy!)
console.log(count ?? "no count");   // 0  (0 is not null/undefined)

console.log(name || "anonymous");   // "anonymous" ("" is falsy!)
console.log(name ?? "anonymous");   // ""  ("" is not null/undefined)

// Safe defaults for potentially null API responses
const config = {
  retries: 0,       // valid setting
  timeout: null,    // explicitly not set
};

const retries = config.retries ?? 3;    // 0 (correct!)
const timeout = config.timeout ?? 5000; // 5000 (correct!)
const missing = config.debug ?? false;  // false (correct!)

console.log(retries, timeout, missing);

Nullish assignment operators

// ??= assign only if null or undefined
let username = null;
username ??= "guest";
console.log(username);  // "guest"

let score = 0;
score ??= 100;          // 0 is not null/undefined
console.log(score);     // 0  (unchanged)

// ||= assign only if falsy
let title = "";
title ||= "Untitled";
console.log(title);     // "Untitled" ("" is falsy)

// &&= assign only if truthy
let admin = true;
admin &&= "super-admin";
console.log(admin);     // "super-admin" (was truthy)

// Practical: initialise object property once
const cache = {};
cache.hits ??= 0;
cache.hits++;
console.log(cache.hits);  // 1

Common Mistakes

  • Using `||` instead of `??` for defaults when 0 or `""` are valid values `0 || 5` gives 5, not 0
  • Optional chaining doesn't protect against calling a method that exists but throws it only guards against null/undefined
  • Over-chaining `?.` on everything hides bugs if a value should always be present, a crash is better than a silent undefined

Note

A good rule: use `??` for defaults (protecting against unset values), use `||` when you want to replace any falsy value. Use `?.` when a property is genuinely optional not just when you're unsure if data is valid.

Exercises

Write JavaScript code to solve each exercise. Run it and check your output.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

What does `user?.address?.city` return if `user` is null?