JavaScript Nullish Coalescing and Optional Chaining

Two modern JavaScript operators — nullish coalescing (??) and optional chaining (?.) — make it much easier to work with data that might be missing, null, or undefined. They eliminate long chains of if checks and prevent the dreaded "Cannot read properties of undefined" error.

Part 1: Nullish Coalescing Operator ??

The ?? operator returns the right-hand side value when the left-hand side is null or undefined. For any other value — including 0, false, and empty string "" — it returns the left-hand side.

Diagram: How ?? Works

value ?? fallback

Is value null or undefined?
  YES → return fallback
  NO  → return value (even if value is 0, false, "")

Basic Example

let username = null;
let display = username ?? "Guest";
console.log(display); // "Guest"

let score = 0;
let finalScore = score ?? 100;
console.log(finalScore); // 0   (0 is NOT null or undefined)

let name = "";
let label = name ?? "Anonymous";
console.log(label); // ""   (empty string is NOT null or undefined)

Why Not Just Use ||?

The || operator treats 0, false, and "" as falsy — and replaces them with the fallback. This is a bug when those values are valid.

let volume = 0;

// BUG with ||
let setting1 = volume || 50;   // 50  — wrong! 0 is a valid volume
// CORRECT with ??
let setting2 = volume ?? 50;   // 0   — correct!

Diagram: || vs ??

value = 0

value || 50:
  Is 0 falsy? YES → returns 50 ← BUG (0 is a valid value)

value ?? 50:
  Is 0 null/undefined? NO → returns 0 ← CORRECT

Nullish Assignment ??=

The ??= operator assigns a value only if the variable is currently null or undefined.

let config = {
  timeout: null,
  retries: 3
};

config.timeout ??= 5000;
config.retries ??= 10;

console.log(config.timeout); // 5000  (was null, now assigned)
console.log(config.retries); // 3     (was 3, not null — unchanged)

Part 2: Optional Chaining Operator ?.

The ?. operator lets you safely read nested properties without checking every level for null or undefined. If any part of the chain is null or undefined, it stops and returns undefined instead of throwing an error.

The Problem Without Optional Chaining

let user = null;

// This throws: TypeError: Cannot read properties of null
console.log(user.profile.name);

// Old fix — long if chain
if (user && user.profile && user.profile.name) {
  console.log(user.profile.name);
}

Solution With Optional Chaining

let user = null;
console.log(user?.profile?.name); // undefined — no error!

let user2 = {
  profile: {
    name: "Sunita",
    city: "Delhi"
  }
};
console.log(user2?.profile?.name); // "Sunita"
console.log(user2?.profile?.age);  // undefined (age doesn't exist)

Diagram: Optional Chaining Step by Step

user?.profile?.name

Step 1: Is user null or undefined?
  YES → stop, return undefined
  NO  → continue to .profile

Step 2: Is user.profile null or undefined?
  YES → stop, return undefined
  NO  → continue to .name

Step 3: Return user.profile.name

Real-World Example: API Response

// API might return incomplete data
let response = {
  data: {
    user: {
      name: "Rahul"
      // address is missing
    }
  }
};

// Safe access — no errors even if address is missing
let city = response?.data?.user?.address?.city;
console.log(city); // undefined — not an error

// Combine with ?? for a fallback
let displayCity = response?.data?.user?.address?.city ?? "City not set";
console.log(displayCity); // "City not set"

Diagram: ?? and ?. Working Together

response?.data?.user?.address?.city ?? "City not set"
                               │
             city is undefined (address missing)
                               │
              ?? kicks in → "City not set"

Optional Chaining with Methods

Use ?.() to call a method only if it exists.

let logger = {
  log: function(msg) {
    console.log("LOG:", msg);
  }
};

logger.log?.("Hello");  // LOG: Hello
logger.warn?.("Oops");  // undefined — warn doesn't exist, no error

let noLogger = null;
noLogger?.log?.("Test"); // undefined — no error

Optional Chaining with Arrays

Use ?.[index] to safely access array elements on a value that might be null.

let data = null;

console.log(data?.[0]);        // undefined — no error
console.log(data?.[0]?.name);  // undefined — no error

let arr = [{ name: "Sita" }, { name: "Gita" }];
console.log(arr?.[0]?.name);   // "Sita"
console.log(arr?.[5]?.name);   // undefined — index out of range, safe

Combining Both Operators in Real Code

function getUserDisplayName(user) {
  return user?.profile?.displayName
      ?? user?.name
      ?? "Anonymous";
}

console.log(getUserDisplayName(null));
// "Anonymous"

console.log(getUserDisplayName({ name: "Dev" }));
// "Dev"

console.log(getUserDisplayName({ name: "Dev", profile: { displayName: "DevKing" } }));
// "DevKing"

Diagram: Layered Fallback Logic

user?.profile?.displayName  → undefined (no profile)
    ??
user?.name                  → "Dev" ← found!
    ??
"Anonymous"                 ← not reached

Result: "Dev"

Quick Reference

OperatorPurposeReturns fallback when
??Default value for null/undefinedLeft side is null or undefined
??=Assign if null/undefinedVariable is null or undefined
?.Safe property accessAny step in chain is null/undefined
?.()Safe method callMethod does not exist
?.[i]Safe array accessArray or index does not exist

Summary

Nullish coalescing (??) provides a fallback only for null or undefined — unlike ||, it respects 0, false, and empty strings as valid values. Optional chaining (?.) safely navigates nested properties and method calls without throwing errors when any step is missing. Together, they eliminate defensive coding boilerplate and make JavaScript code that handles real-world, incomplete data far shorter and more readable.

Leave a Comment

Your email address will not be published. Required fields are marked *