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
| Operator | Purpose | Returns fallback when |
|---|---|---|
?? | Default value for null/undefined | Left side is null or undefined |
??= | Assign if null/undefined | Variable is null or undefined |
?. | Safe property access | Any step in chain is null/undefined |
?.() | Safe method call | Method does not exist |
?.[i] | Safe array access | Array 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.
