Often you want to use a default value when something is missing. You've seen the || trick for this:
const userName = undefined;
console.log(userName || "Guest");
It prints
Guest
|| returns the right side whenever the left side is falsy. That's usually fine... but remember the falsy list from Grade 4? It includes 0 and "". Look what happens:
const settings = { volume: 0, nickname: "" };
console.log(settings.volume || 50);
console.log(settings.nickname || "Anonymous");
It prints
50 Anonymous
The user deliberately set their volume to 0 (silence, please!), and we replaced it with 50. Oops. That's a bug.
The nullish coalescing operator ?? fixes this. It only falls back to the right side if the left side is null or undefined (together called "nullish"). Every other value, including 0, "" and false, is kept:
const settings = { volume: 0, nickname: "" };
console.log(settings.volume ?? 50);
console.log(settings.nickname ?? "Anonymous");
console.log(settings.theme ?? "light");
It prints
0 light
The volume stays at 0, the nickname stays as the empty string (that blank line is it), and only the genuinely missing theme gets the default.
| Expression | || result | ?? result |
|---|---|---|
undefined + default | default | default |
null + default | default | default |
0 + default | default ⚠️ | 0 |
"" + default | default ⚠️ | "" |
false + default | default ⚠️ | false |
Use ?? when you want a default only for missing values (this is usually what you want). Use || when you want a default for any falsy value, including empty strings and zero. When in doubt, ?? is the safer choice.
?. and ?? are best friends, and you'll often see them together:
const response = { data: { user: { name: "Elsa" } } };
const empty = {};
console.log(response.data?.user?.name ?? "Unknown user");
console.log(empty.data?.user?.name ?? "Unknown user");
It prints
Elsa Unknown user
"Try to dig out the name. If anything along the way is missing, use "Unknown user" instead." Safe, short and readable.