Engrain by ByteRush

JS.08.02 Junior· 8 minCore — asked often

Optional chaining and ??: safe access without hiding real values

Read nested data that may be missing with ?., pick fallbacks with ?? instead of ||, and use ??=, ||= and &&=. With the 0 and empty-string traps.

Comes up in: JavaScript, Recruiter screen

Learn#

Priya’s music app crashes for new users: user.profile.avatar.url throws because new users have no profile. Old code guarded it with user && user.profile && user.profile.avatar && ….

Optional chaining, ?., stops and returns undefined when the value before it is null or undefined. It short-circuits: nothing to the right runs.

const user = { name: "Priya" };
let calls = 0;
console.log(user.profile?.avatar.url);
console.log(user.profile?.avatar[calls++], calls);
console.log(user.save?.());

Output (verified)

undefined
undefined 0
undefined

Her second bug: a muted user’s volume of 0 becomes 50. || falls back for every falsy value: 0, "", false, NaN. Nullish coalescing, ??, falls back only for null or undefined.

|| versus ?? when the value is 0Step 1 of 3

State

  • settings = { volume: 0 }

settings.volume is 0: the user muted the sound on purpose.

Read the steps as text
  1. settings.volume is 0: the user muted the sound on purpose.
  2. settings.volume || 50 sees a falsy 0 and picks 50. The user's choice is lost.
  3. settings.volume ?? 50 falls back only for null or undefined. 0 is kept.

Predict#

Predict first

What does console.log("" ?? "x", 0 || "y", null ?? 0) print?

Interview angle#

Say it like this — about 30 seconds

“Optional chaining returns undefined instead of throwing when the value before ?. is null or undefined, and it skips the rest of the expression. Nullish coalescing gives a fallback only for null or undefined, while || falls back for any falsy value, so it overwrites 0, empty strings and false. I use ?? for settings and counts. The assignment forms ??=, ||= and &&= assign only when that condition holds.”

Stays on your device. Nothing is uploaded.
Follow-up What is the difference between ?? and ||?
|| falls back for any falsy value (0, "", false, NaN, null, undefined). ?? falls back only for null and undefined.
Follow-up Can you mix ?? with || without parentheses?
No. a || b ?? c is a SyntaxError; you must write (a || b) ?? c.
Follow-up What does a.b ??= 5 do?
It assigns 5 only if a.b is null or undefined. Otherwise it does nothing, not even run the setter.

Practice#

Guided

Fix the four functions. Each one either crashes on missing data or throws away a real value.

Done when

  • city never throws, even for undefined or a user with no address.
  • pageSize({ pageSize: 0 }) returns 0.
  • greet works whether or not format exists.
  • ensureTags keeps an existing empty array or empty string.
Your solution
Ctrl/⌘ + Enter

Remember#

Try to answer each card before you open it. Then add them to your reviews.

When does a?.b return undefined without reading b?

When a is null or undefined.

Which values make ?? use its fallback?

Only null and undefined.

What does this print?
console.log(0 || 5, 0 ?? 5)
5 0
What does x ||= y do?

Assigns y to x only if x is falsy.

Go deeper

Four layers. Stop at the one your interview needs; each ends with a quick check.

The core ideaEvery round

Three forms: property a?.b, computed a?.[key], and call fn?.(). The call form checks that fn is not null or undefined; it still throws if fn is a non-function such as a number.

Check yourself: Which forms of optional chaining exist?

a?.b, a?.[key] and fn?.()

How it works underneathSenior rounds

Short-circuiting covers the whole chain after ?., so a?.b.c.d does not throw when a is null. But (a?.b).c does throw, because the parentheses end the chain Source: MDN: Optional chaining.

Check yourself: In a?.b.c.d, if a is null, is .c read?

No. The whole chain short-circuits to undefined.

Edge cases and trapsWhere people slip

Mixing ?? with || or && without parentheses is a SyntaxError, so the meaning is never ambiguous Source: MDN: Nullish coalescing operator. Optional chaining cannot be on the left of an assignment: a?.b = 1 is a SyntaxError.

Check yourself: Is a || b ?? c valid JavaScript?

No, it is a SyntaxError; add parentheses.

In productionStaff-level answers

The logical assignments short-circuit too: cache[key] ??= compute() runs compute only when the entry is missing, opts.debug ||= false sets a falsy value, and user &&= normalize(user) changes it only if it exists.
Validate API data at the boundary so you need fewer ?. deeper in the code.

Check yourself: Why prefer cache[key] ??= compute() over an if check?

It is shorter, and compute only runs when the entry is missing.

Finished the five steps? Mark it, and its cards join your reviews.

Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

Interview questions this answers

  • What is the difference between ?? and ||?