The '??' operator fixes a long-standing footgun with '||' for default values: it only falls back on null or undefined, correctly preserving legitimate falsy values like 0, false, and empty strings.
1Nullish Coalescing | JavaScript Tutorial - In-Depth Guide Part 1
The '??' operator returns its right-hand side only when the left-hand side is null or undefined — unlike '||', which falls back on any falsy value.
const volume = 0;
volume || 10; // 10 (wrong!)
volume ?? 10; // 0 (correct)?? vs ||
2Nullish Coalescing | JavaScript Tutorial - In-Depth Guide Part 2
'??' is the precise tool for 'use this value unless it was never actually set', as opposed to 'use this value unless it's falsy'.
function greet(name) {
const who = name ?? 'friend';
return `Hello, ${who}!`;
}Presence, Not Truthiness
3Nullish Coalescing | JavaScript Tutorial - In-Depth Guide Part 3
JavaScript forbids mixing '??' directly with '&&' or '||' without parentheses, to avoid ambiguous precedence.
a || b ?? c; // SyntaxError
(a || b) ?? c; // OKMixing Requires Parens
4Nullish Coalescing | JavaScript Tutorial - In-Depth Guide Part 4
'??' chains left-to-right, returning the first operand that isn't null or undefined.
const theme = userTheme ?? orgTheme ?? 'light';Fallback Chains
5Nullish Coalescing | JavaScript Tutorial - In-Depth Guide Part 5
'??=' is the assignment form: it only assigns a new value to a variable if it is currently null or undefined.
let config = {};
config.retries ??= 3;The ??= Operator
6Step-by-Step Breakdown
The '??' operator returns its right-hand side only when the left-hand side is null or undefined — unlike '||', which falls back on any falsy value.
Checkpoint: What does 0 ?? 10 evaluate to?
- →0, because 0 is not nullish
- →10, because 0 is falsy
'??' is the precise tool for 'use this value unless it was never actually set', as opposed to 'use this value unless it's falsy'.
JavaScript forbids mixing '??' directly with '&&' or '||' without parentheses, to avoid ambiguous precedence.
Checkpoint: Can you write a || b ?? c without parentheses?
- →Yes, JS resolves it left-to-right
- →No, it throws a SyntaxError without explicit parentheses
'??' chains left-to-right, returning the first operand that isn't null or undefined.
'??=' is the assignment form: it only assigns a new value to a variable if it is currently null or undefined.
Next, we'll explore 'Logical Assignment Operators'.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Use `??` for ARIA Attribute Defaults Involving Booleans
An attribute like `aria-pressed={isPressed ?? false}` correctly preserves an explicit `false` value, whereas `isPressed || false` would behave identically here but the habit of using `||` for booleans elsewhere risks the same falsy-value bug on numeric ARIA values like `aria-valuenow`.
SEO Implications
- 1
Correct Defaults Prevent Silent Content Bugs
A `||`-based default bug that replaces a legitimate 0 (like a "0 reviews" count) with a different fallback value can render incorrect content that misleads both users and search engines indexing structured data.
Best Practices
Default to `??` Over `||` for Value Defaults
Unless you specifically want to replace every falsy value (rare), `??` is almost always the operator you actually mean when writing 'default to X if not provided'.
Use `??=` for Lazy Initialization
A property that should only be set once, the first time it is undefined, is a perfect fit for `??=` instead of a verbose `if (x === undefined) x = ...` block.
Frequent Bugs
A numeric form field defaulted with `value || 0` silently replaces a user-entered `0` with the fallback, corrupting form state.
Switch to `value ?? 0`, which only substitutes the default when the value is actually null or undefined, leaving a real 0 untouched.
Writing `a || b ?? c` directly causes a SyntaxError at parse time, breaking the build.
Add explicit parentheses to state the intended precedence, e.g. `(a || b) ?? c`.
Real-World Examples
Defaulting a Pagination Page Size
An API client needed to default a `pageSize` query parameter to 20 only when the caller genuinely omitted it, while still allowing an explicit `0` to mean "no items" for a specific edge case.
function fetchPage({ pageSize } = {}) {
const size = pageSize ?? 20;
return fetch(`/items?limit=${size}`);
}