Real data has gaps; these operators replace long chains of && checks and buggy || defaults.
Reading a property of undefined or null throws a TypeError. Optional chaining ?. stops evaluation and returns undefined if the value on its left is null or undefined:
const city = user?.address?.city; // undefined instead of a crashIt has three forms:
obj?.prop— property accessobj?.[expr]— bracket accessfn?.(args)— call only iffnexists, e.g.options.onDone?.()
The nullish coalescing operator a ?? b returns b only when a is null or undefined. Compare it with ||, which falls back on any falsy value:
const volume = settings.volume ?? 50; // keeps a valid 0
const bad = settings.volume || 50; // 0 becomes 50!Use ?? for defaults whenever 0, "" or false are legitimate values.
There are also logical assignment operators:
a ??= b— assign only ifais null/undefineda ||= b— assign ifais falsya &&= b— assign ifais truthy
They're handy for filling in defaults: config.retries ??= 3.
Don't sprinkle ?. everywhere: if a value must exist, a crash with a clear error is more useful than an undefined that propagates silently. Use it where absence is genuinely expected — optional fields, API responses, optional callbacks.
One syntax note: you can't combine ?? with || or && without parentheses; a || b ?? c is a SyntaxError.
Example
const order = { id: 7, customer: { name: "Ada" }, discount: 0 };
console.log(order.customer?.name); // "Ada"
console.log(order.shipping?.address.city); // undefined (no crash)
console.log(order.items?.[0]); // undefined
console.log(order.discount ?? 10); // 0 (0 is kept)
console.log(order.discount || 10); // 10 (0 is falsy)
const options = { onDone: undefined };
options.onDone?.(); // no call, no error
order.notes ??= "none";
order.discount ||= 5;
console.log(order.notes, order.discount); // none 5Remember
?.returnsundefinedinstead of throwing when the left side is null or undefined??defaults only for null/undefined;||also replaces 0, "" and false??=,||=,&&=assign conditionally
Watch out for
- Using
||for a default when 0 or an empty string is a valid value.