Suggest an editImprove this articleRefine the answer for “Optional chaining (?.) and nullish coalescing (??) in JavaScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Optional chaining** (`?.`) short-circuits to `undefined` when any part of a property chain is `null` or `undefined`. **Nullish coalescing** (`??`) returns the right side only when the left is `null` or `undefined`, not for `0`, `""`, or `false`. ```javascript user?.address?.city // undefined, no error user?.address?.city ?? "NYC" // "NYC" as fallback 0 ?? 10 // 0 (preserved - zero is valid) 0 || 10 // 10 (|| replaces 0) ``` **Key:** use `??` instead of `||` when `0`, `false`, or `""` are valid values.Shown above the full answer for quick recall.Answer (EN)Image**Optional chaining** (`?.`) and **nullish coalescing** (`??`) are two ES2020 operators that solve different problems: `?.` prevents crashes on missing properties, `??` provides defaults without replacing valid falsy values like `0`, `""`, or `false`. ## Theory ### TL;DR - `?.` short-circuits to `undefined` at the first `null` or `undefined` in the chain - `??` returns the right side only when the left is `null` or `undefined`, not for `0`, `""`, or `false` - `||` returns the right side for any falsy value, including `0` and `false` - that is often a bug - Use them together: `user?.profile?.name ?? "Guest"` - safe access with a fallback - Decision rule: chain with `?.` first, then add a default with `??` at the end ### Quick example ```javascript const user = { name: "Alice" }; // ?. stops at the first null/undefined console.log(user?.address?.city); // undefined (no error) console.log(user?.address?.city ?? "NYC"); // "NYC" (fallback applied) // ?? vs || - the key difference const count = 0; console.log(count ?? 10); // 0 - zero is valid data, ?? leaves it console.log(count || 10); // 10 - || treats 0 as falsy and replaces it ``` The last two lines are the most common source of bugs when working with these operators. If `count` can legitimately be `0`, always use `??`. ### Key difference `?.` is about defensive access. `??` is about value defaulting. They solve different problems and work together naturally. `?.` prevents `TypeError: Cannot read properties of undefined`. `??` makes sure a fallback does not accidentally replace `0` or `false`, which `||` would silently overwrite. ### When to use - **`?.`**: accessing nested objects from API responses, calling optional callbacks, reading config that might not be set - **`??`**: providing defaults for settings where `0`, `""`, or `false` are valid values - **`?.` and `??` together**: `response?.data?.count ?? 0` - safe traversal with a meaningful fallback - **Stick with `||` for truthiness checks**: toggling UI states or treating empty strings as "missing" still suits `||` ### Comparison table | Operator | Returns right side when | Preserves | Common use | |----------|------------------------|-----------|------------| | `?.` | Left is `null`/`undefined` | Returns `undefined` on stop | Safe nested access | | `??` | Left is `null`/`undefined` | `0`, `""`, `false`, `NaN` | Defaults for optional values | | `\|\|` | Left is any falsy value | Only truthy values | Truthiness-based defaults | | `&&` | Left is truthy | N/A | Conditional execution | ### How it works internally Both operators are part of ES2020 and are natively supported in Node.js 14+ and all modern browsers. When the engine hits `obj?.prop`, it checks whether `obj` is `null` or `undefined`. If yes, it returns `undefined` immediately without evaluating the rest. The chain `a?.b?.c?.d` stops at the first nullish value, so nothing after it runs. Babel transpiles both operators for older targets using equivalent conditional checks. ### Common mistakes **Mistake 1: using `||` when you need `??`** ```javascript // Bug: a timeout of 0 means "no delay", but || replaces it const timeout = settings.timeout || 5000; // 5000 even when timeout is 0 const timeout = settings.timeout ?? 5000; // Correct ``` **Mistake 2: redundant `?.` after an explicit check** ```javascript // Unnecessary - address is already confirmed if (user && user.address) { const city = user.address?.city; } // Simpler const city = user?.address?.city; ``` **Mistake 3: forgetting `?.` on optional method calls** ```javascript options.onSuccess(); // TypeError if onSuccess was not passed options.onSuccess?.(); // Returns undefined safely ``` **Mistake 4: expecting `??` to catch all falsy values** ```javascript const message = "" ?? "default"; // "" - empty string is not null/undefined const message = "" || "default"; // "default" - || does catch empty strings ``` ### Real-world usage - React: `props?.user?.avatar ?? "/default.png"` - optional props in components - Express.js: `req?.query?.search ?? ""` - reading optional query params - Redux selectors: `state?.auth?.user?.role ?? "guest"` - nested store access - API responses: `response?.data?.items?.[0]?.id ?? null` - traversing nullable fields - Optional callbacks: `options.onSuccess?.()` - safe calls when callback might not be passed ### Follow-up questions **Q:** What is the difference between `obj?.prop` and `obj && obj.prop`? **A:** Both prevent errors, but the return value differs. `obj && obj.prop` returns the falsy value itself if `obj` is `0` or `""`. `?.` always returns `undefined` when the chain stops. `?.` also signals intent more clearly. **Q:** Why does `0 ?? 10` return `0` but `0 || 10` returns `10`? **A:** `??` checks specifically for `null` or `undefined`, not for falsiness. Zero is falsy but not nullish, so `??` treats it as valid data and leaves it unchanged. **Q:** Can you use optional chaining in destructuring? **A:** Not directly in the destructuring syntax. The workaround is `const { name } = user?.profile ?? {}`. Without `?? {}`, destructuring would throw if `user?.profile` returns `undefined`. **Q:** What happens with multiple `?.` in a chain like `a?.b?.c?.d`? **A:** The whole chain short-circuits at the first `null` or `undefined` and returns `undefined`. Each `?.` is independent. If `a.b` is null, neither `c` nor `d` is evaluated. **Q (senior):** In a loop processing millions of objects, which would you prefer: `obj?.prop ?? default` or `obj && obj.prop || default`? **A:** Modern engines optimize both similarly, and `?.` is a single operator vs two separate operations. The stronger reason to prefer `?.` is clarity: it makes null-safe access obvious at a glance. Profile first before changing anything in a hot path. ## Examples ### Basic: API response in a React component ```javascript function UserProfile({ apiResponse }) { const userName = apiResponse?.data?.user?.name ?? "Anonymous"; const avatarUrl = apiResponse?.data?.user?.avatar ?? "/default-avatar.png"; const isAdmin = apiResponse?.data?.user?.permissions?.isAdmin ?? false; return ( <div> <h1>Hello, {userName}</h1> <img src={avatarUrl} alt={userName} /> {isAdmin && <span>Admin</span>} </div> ); } // Works even when apiResponse is null or data is partially missing ``` The `??` on `isAdmin` matters here. `isAdmin || false` would also work, but `??` makes the intent clear: only substitute `false` when the value was never set. ### Intermediate: optional method calls and array access ```javascript const response = { items: [ { id: 1, process: () => "processed" }, { id: 2 } // No process method ] }; console.log(response.items?.[0]?.process?.()); // "processed" console.log(response.items?.[1]?.process?.()); // undefined - no error console.log(response.items?.[5]?.process?.()); // undefined - index out of bounds const result = response.items?.[1]?.process?.() ?? "default processing"; console.log(result); // "default processing" // Without optional chaining - crashes response.items[1].process(); // TypeError: process is not a function ``` The `?.()` syntax for method calls is easy to forget. It follows the same pattern as `?.prop` but applies to function invocation.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.