Loading...
Loading...
The ?? operator — defaults that respect zero, empty strings, and false.
Module 9 · Modern JavaScript (ES6+)
ES2015 and later additions transformed how JavaScript is written. let and const, template literals, modules, spread/rest, optional chaining, and nullish coalescing are now standard in every modern codebase.
Learn Nullish Coalescing in JavaScript — covering Basics, vs || (OR), ??= Assignment, With ?. with interactive visual examples and step-by-step explanations.
ES2015 (ES6) and the releases that followed added the syntax modern JavaScript is written in today. let and const replaced var, template literals replaced string concatenation, and import/export replaced global script tags.
This module covers the ES6+ features you will see in every codebase and job interview. Each chapter shows the old pattern alongside the modern equivalent so you can read legacy code and write idiomatic JavaScript.
Understanding nullish coalescing is essential for every JavaScript developer. It shows up in frontend UI code, backend APIs, and framework internals — and getting it wrong leads to bugs that are hard to trace. This chapter builds intuition with visuals so the behavior sticks.
?? returns the right side only for null/undefined.
// ?? — nullish coalescing operator: // Returns RIGHT side if LEFT is null or undefined // Returns LEFT side for everything else null ?? "default"; // "default" undefined ?? "default"; // "default" // These are NOT nullish — left side is returned: 0 ?? "default"; // 0 "" ?? "default"; // "" false ?? "default"; // false NaN ?? "default"; // NaN // Think of it as: "use this value, unless it's missing" const name = user.name ?? "Anonymous"; const count = response.total ?? 0; const enabled = settings.darkMode ?? true;
Nullish = null or undefined
Only these two values trigger the default. Zero, empty string, false, and NaN are all valid values that ?? preserves.
The key difference: what triggers the fallback.
// || triggers fallback for ALL falsy values: 0 || 42; // 42 (0 is falsy) "" || "default"; // "default" (empty string is falsy) false || true; // true (false is falsy) null || "backup"; // "backup" // ?? triggers fallback ONLY for null/undefined: 0 ?? 42; // 0 ← preserves zero! "" ?? "default"; // "" ← preserves empty string! false ?? true; // false ← preserves false! null ?? "backup"; // "backup"
|| catches all falsy values (0, '', false, null, undefined, NaN). ?? only catches null and undefined.
| Value | x || "fb" | x ?? "fb" |
|---|---|---|
| null | "fb" | "fb" |
| undefined | "fb" | "fb" |
| 0 | "fb" | 0 |
| "" | "fb" | "" |
| false | "fb" | false |
| "hi" | "hi" | "hi" |
Assign only if the variable is null/undefined.
// Nullish coalescing assignment (??=): // Assigns only if the left side is null/undefined let name = null; name ??= "Anonymous"; // name = "Anonymous" (was null) let count = 0; count ??= 10; // count = 0 (was NOT null/undefined, so unchanged!) // Equivalent to: // x ??= y → x = x ?? y → if (x == null) x = y; // Useful for lazy initialization: function getCache() { this.cache ??= {}; // create once this.cache.hits ??= 0; // init counter once return this.cache; } // Compare with other assignment operators: let a = null; a ||= "default"; // assigns if falsy (0, "", false, null, undefined) a &&= "value"; // assigns if truthy a ??= "default"; // assigns if null/undefined ONLY
The perfect pair — safe access + safe defaults.
// ?. + ?? = safe access with fallback: const theme = user?.settings?.theme ?? "light"; const avatar = profile?.images?.avatar ?? "/default.png"; const count = response?.data?.items?.length ?? 0; // Without this combo (old verbose way): const theme = user && user.settings && user.settings.theme ? user.settings.theme : "light"; // Real-world API handling: async function getUser(id) { const res = await fetch(`/api/users/${id}`); const data = await res.json(); return { name: data?.name ?? "Unknown", email: data?.email ?? null, avatar: data?.profile?.avatar?.url ?? "/placeholder.png", role: data?.permissions?.role ?? "viewer", lastLogin: data?.activity?.lastLogin ?? "Never", }; } // DOM with fallback: const title = document.querySelector("h1")?.textContent ?? "Untitled"; const width = element?.getBoundingClientRect()?.width ?? 0;
Common patterns with nullish coalescing.
// 1. Configuration with defaults: function createServer(options) { const port = options?.port ?? 3000; const host = options?.host ?? "localhost"; const debug = options?.debug ?? false; // port: 0 is valid, debug: false is valid } // 2. Chaining with ??: const value = primary ?? secondary ?? tertiary ?? "fallback"; // First non-nullish value wins // 3. Form values (empty string is valid): const search = input.value ?? ""; // Only defaults if value is somehow null/undefined // Preserves "" (user cleared the field intentionally) // 4. Numeric defaults: const timeout = config.timeout ?? 5000; const retries = config.retries ?? 3; const delay = config.delay ?? 0; // 0 is preserved! // ⚠️ Cannot mix with || or && without parentheses: // a ?? b || c → SyntaxError! // a || b ?? c → SyntaxError! // Must use parens: (a ?? b) || c // ✓ a ?? (b || c) // ✓
Common questions about nullish coalescing.