[{"data":1,"prerenderedAt":170},["ShallowReactive",2],{"qa-\u002Fjavascript\u002Fmodern\u002Foptional-chaining-nullish":3},{"page":4,"siblings":153,"blog":167},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":12,"path":20,"questions":21,"related":144,"seo":145,"seoDescription":146,"stem":147,"subtopic":148,"topic":149,"topicSlug":150,"updated":151,"__hash__":152},"qa\u002Fjavascript\u002Fmodern\u002Foptional-chaining-nullish.md","Optional Chaining Nullish",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","JavaScript","javascript",{},true,"\u002Fjavascript\u002Fmodern\u002Foptional-chaining-nullish",[22,27,31,35,39,43,47,51,55,59,63,67,71,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140],{"id":23,"difficulty":24,"q":25,"a":26},"what-is-optional-chaining","easy","What is optional chaining?","**Optional chaining** (`?.`) accesses a nested property only if the value to its\nleft is **not `null` or `undefined`**; otherwise the whole expression\nshort-circuits and returns `undefined` instead of throwing.\n\n```js\nconst user = { profile: { name: 'Ada' } }\nconsole.log(user.profile?.name)      \u002F\u002F 'Ada'\nconsole.log(user.account?.balance)   \u002F\u002F undefined  no throw\n\u002F\u002F console.log(user.account.balance) \u002F\u002F TypeError: Cannot read 'balance' of undefined\n```\n\nIt replaces long `a && a.b && a.b.c` guards. Pitfall: it guards against `null`\u002F\n`undefined` only — it does **not** protect against other errors like calling a\nnon-function.\n",{"id":28,"difficulty":24,"q":29,"a":30},"optional-chaining-properties","How does ?. work on nested property access?","`a?.b` evaluates `a`; if it's `null`\u002F`undefined` it returns `undefined`,\notherwise it accesses `b`. Chaining several `?.` guards each link in the path.\n\n```js\nconst data = { a: { b: null } }\nconsole.log(data?.a?.b?.c)           \u002F\u002F undefined  stops safely at b being null\n```\n\nImportantly, `?.` only checks the value **immediately to its left**. Pitfall:\n`data.a?.b.c` guards `a` but **not** `b` — if `b` is `null`, accessing `.c`\nstill throws. Put `?.` at every uncertain link.\n",{"id":32,"difficulty":14,"q":33,"a":34},"optional-chaining-methods","How do you optionally call a method that might not exist?","Use `obj.method?.()`. If `method` is `null` or `undefined`, the call is skipped\nand the expression yields `undefined`; otherwise the method runs normally.\n\n```js\nconst api = { log: () => 'logged' }\nconsole.log(api.log?.())             \u002F\u002F 'logged'\nconsole.log(api.track?.())           \u002F\u002F undefined  no track method, no throw\n```\n\nHandy for optional callbacks: `onChange?.(value)`. Pitfall: if `method` exists\nbut is **not a function** (e.g. a number), `?.()` still throws `TypeError: not a\nfunction` — `?.` only guards `null`\u002F`undefined`, not wrong types.\n",{"id":36,"difficulty":14,"q":37,"a":38},"optional-chaining-arrays","How does optional chaining work with array\u002Fdynamic access?","Use `arr?.[index]`. The `?.` before the bracket guards the array itself being\n`null`\u002F`undefined` before the element is read.\n\n```js\nconst result = { items: ['a', 'b'] }\nconsole.log(result.items?.[0])       \u002F\u002F 'a'\nconsole.log(result.tags?.[0])        \u002F\u002F undefined  no tags array, no throw\n```\n\nSame applies to computed keys: `obj?.[key]`. Pitfall: `arr?.[0]` guards `arr`,\nnot the element — if `arr` is `[]`, `arr?.[0]` is `undefined` (fine), but\n`arr?.[0].name` throws because element `0` is `undefined`.\n",{"id":40,"difficulty":14,"q":41,"a":42},"short-circuiting","What does short-circuiting mean in optional chaining?","When `?.` hits a `null`\u002F`undefined`, it **stops evaluating the rest of the\nchain** and returns `undefined` immediately — nothing to the right runs,\nincluding function calls.\n\n```js\nlet calls = 0\nconst obj = null\nconst r = obj?.method(calls++)       \u002F\u002F undefined\nconsole.log(calls)                   \u002F\u002F 0  method() and calls++ never ran\n```\n\nThe entire chain after the short-circuit is skipped, side effects included.\nPitfall: people assume arguments still evaluate — they don't, so relying on a\nside effect inside a short-circuited call is a silent bug.\n",{"id":44,"difficulty":24,"q":45,"a":46},"nullish-coalescing","What is the nullish coalescing operator ??","`a ?? b` returns `a` unless it is **`null` or `undefined`**, in which case it\nreturns `b`. It provides a default only for \"no value\", not for any falsy value.\n\n```js\nconst port = userPort ?? 3000        \u002F\u002F use userPort unless it's null\u002Fundefined\nconsole.log(0 ?? 5)                  \u002F\u002F 0  0 is a real value, kept\nconsole.log(null ?? 5)               \u002F\u002F 5  null -> fallback\n```\n\nIt treats `0`, `''`, `false`, and `NaN` as legitimate values. Pitfall: don't\nreach for `??` when you actually want to reject *all* falsy values — that's `||`.\n",{"id":48,"difficulty":14,"q":49,"a":50},"nullish-vs-or","What is the difference between ?? and ||?","`||` falls back on **any falsy** value (`0`, `''`, `false`, `NaN`, `null`,\n`undefined`). `??` falls back only on **`null`\u002F`undefined`**. The difference\nmatters whenever a falsy value is valid.\n\n```js\nconst count = 0\nconsole.log(count || 10)             \u002F\u002F 10  treats valid 0 as \"missing\"\nconsole.log(count ?? 10)             \u002F\u002F 0   keeps the real 0\nconsole.log('' || 'default')         \u002F\u002F 'default'  empty string lost\nconsole.log('' ?? 'default')         \u002F\u002F ''  empty string kept\n```\n\nUse `??` for defaults of numbers\u002Fstrings\u002Fbooleans. Pitfall: blindly migrating\nevery `||` to `??` (or vice-versa) changes behavior for zero\u002Fempty inputs — a\ncommon subtle regression.\n",{"id":52,"difficulty":14,"q":53,"a":54},"when-to-use-or","When is || still the right choice over ???","Use `||` when you genuinely want **any falsy value** to trigger the fallback —\ne.g. treating empty string, `0`, or `false` the same as \"absent.\"\n\n```js\nconst name = input.name || 'Anonymous'   \u002F\u002F '' should also become Anonymous\nconst items = response.list || []        \u002F\u002F falsy\u002Fempty -> safe default array\n```\n\nHere an empty string genuinely means \"no name,\" so `||` is correct and `??`\nwould let `''` through. Pitfall: the choice is semantic — ask \"is a falsy value a\nlegitimate value here?\" If yes use `??`; if no, `||` is fine.\n",{"id":56,"difficulty":14,"q":57,"a":58},"logical-assignment-nullish","What does the ??= operator do?","`a ??= b` assigns `b` to `a` **only if `a` is currently `null` or `undefined`**.\nIt's shorthand for `a = a ?? b`, but with a key twist: it assigns only when\nneeded.\n\n```js\nconst config = { timeout: 0 }\nconfig.timeout ??= 1000              \u002F\u002F stays 0  (0 isn't nullish)\nconfig.retries ??= 3                 \u002F\u002F becomes 3  (was undefined)\nconsole.log(config)                  \u002F\u002F { timeout: 0, retries: 3 }\n```\n\nIt only writes when the left side is nullish, so existing valid values (even\nfalsy ones) survive. Pitfall: confusing it with `||=`, which would overwrite the\n`0`.\n",{"id":60,"difficulty":14,"q":61,"a":62},"logical-assignment-or","What does ||= do and how does it differ from ??=?","`a ||= b` assigns `b` when `a` is **falsy** (`a = a || b`); `a ??= b` assigns\nonly when `a` is **nullish**. The split mirrors the `||` vs `??` distinction.\n\n```js\nlet x = 0\nx ||= 5                              \u002F\u002F x = 5  overwrote valid 0\nlet y = 0\ny ??= 5                              \u002F\u002F y = 0  kept valid 0\n```\n\nBoth **short-circuit**: if no assignment is needed, the right side never\nevaluates (no side effects, no setter triggered). Pitfall: using `||=` to set a\ndefault on a numeric\u002Fboolean field clobbers legitimate `0`\u002F`false`.\n",{"id":64,"difficulty":14,"q":65,"a":66},"logical-assignment-and","What does the &&= operator do?","`a &&= b` assigns `b` to `a` **only if `a` is truthy** (`a = a && b`). It's used\nto update a value only when it already exists.\n\n```js\nlet user = { name: 'Ada' }\nuser.name &&= user.name.toUpperCase()\nconsole.log(user.name)               \u002F\u002F 'ADA'  updated because it was truthy\nlet empty = null\nempty &&= 'x'                        \u002F\u002F stays null  falsy, left alone\n```\n\nLike the others it short-circuits — `b` only evaluates when `a` is truthy.\nPitfall: it's the least common of the three; people often reach for an `if` when\n`&&=` would read more cleanly (or vice versa where `if` is clearer).\n",{"id":68,"difficulty":14,"q":69,"a":70},"combining-optional-and-nullish","How do you combine ?. with ?? for a safe default?","This is the canonical pair: `?.` safely walks a possibly-missing path and yields\n`undefined`, then `??` supplies a default for that `undefined`.\n\n```js\nconst user = { settings: null }\nconst theme = user?.settings?.theme ?? 'light'\nconsole.log(theme)                   \u002F\u002F 'light'  safe walk + default\n```\n\n`?.` handles the \"path might not exist,\" `??` handles the \"so use a fallback.\"\nPitfall: using `||` instead of `??` here would also override a legitimate\n`theme` of `''` or `0`, which `??` correctly preserves.\n",{"id":72,"difficulty":73,"q":74,"a":75},"precedence-with-nullish","hard","Why must you parenthesize ?? when mixing it with || or &&?","JavaScript **forbids** combining `??` with `||` or `&&` without parentheses — it's\na **syntax error** by design, because the intended precedence is ambiguous to\nreaders.\n\n```js\n\u002F\u002F const x = a || b ?? c             \u002F\u002F SyntaxError\nconst x = (a || b) ?? c              \u002F\u002F explicit grouping required\nconst y = a || (b ?? c)              \u002F\u002F the other grouping\n```\n\nThe language forces you to disambiguate rather than guessing. Pitfall: this is a\ncompile-time error, not a runtime one — copying a clever one-liner from `&&`\u002F`||`\nland into a `??` expression won't even parse.\n",{"id":77,"difficulty":73,"q":78,"a":79},"optional-chaining-not-assignment","Can you use optional chaining on the left side of an assignment?","No. `?.` is only valid for **reading** (and deleting). Using it as an assignment\ntarget is a **syntax error** — you can't conditionally write through it.\n\n```js\nconst obj = { a: {} }\n\u002F\u002F obj?.a?.b = 5                     \u002F\u002F SyntaxError — invalid assignment target\nif (obj?.a) obj.a.b = 5             \u002F\u002F guard, then assign normally\n```\n\n`delete obj?.a.b` is allowed (short-circuits to a no-op if `obj` is nullish), but\nassignment is not. Pitfall: people expect symmetric read\u002Fwrite support and are\nsurprised the parser rejects the assignment form outright.\n",{"id":81,"difficulty":73,"q":82,"a":83},"optional-chaining-overuse","What is the danger of over-using optional chaining?","Sprinkling `?.` everywhere **hides real bugs**. If a value should never be\n`null`, guarding it with `?.` silently swallows the case where it unexpectedly is,\nturning a loud crash into a quiet `undefined` that surfaces far away.\n\n```js\n\u002F\u002F a required user that's accidentally null:\nconst name = user?.profile?.name    \u002F\u002F becomes undefined, no signal something broke\nconst name2 = user.profile.name     \u002F\u002F throws loudly at the actual fault line\n```\n\nUse `?.` only where absence is **legitimate and expected**, not as a blanket\ncrash-suppressor. Pitfall: defensive `?.` everywhere defers the error to a\nconfusing downstream location, making bugs far harder to trace.\n",{"id":85,"difficulty":73,"q":86,"a":87},"nullish-default-vs-destructuring-default","How does ?? differ from a destructuring default?","Both default on `undefined`, but a **destructuring default** does **not** trigger\non `null`, whereas `??` does. So they diverge whenever a value is explicitly\n`null`.\n\n```js\nconst { x = 1 } = { x: null }\nconsole.log(x)                       \u002F\u002F null  \u003C- destructuring default ignores null\nconst y = ({ x: null }).x ?? 1\nconsole.log(y)                       \u002F\u002F 1     \u003C- ?? catches null too\n```\n\nUse a destructuring default for \"missing key,\" and `??` (or both) when `null` is\nalso a \"use the fallback\" signal. Pitfall: assuming `{ x = d }` and `x ?? d`\nbehave identically — they differ precisely on `null`.\n",{"id":89,"difficulty":14,"q":90,"a":91},"optional-call-on-array-method","How do you safely call a method on a possibly-missing array?","Chain `?.` before the method call: `arr?.map(...)`. If `arr` is `null`\u002F\n`undefined`, the whole call short-circuits to `undefined`.\n\n```js\nconst data = {}\nconst upper = data.tags?.map(t => t.toUpperCase())\nconsole.log(upper)                   \u002F\u002F undefined  no throw on missing tags\nconst safe = data.tags?.map(t => t) ?? []  \u002F\u002F fall back to empty array\n```\n\nPair with `?? []` if downstream code expects an array. Pitfall: `data.tags?.map`\nreturning `undefined` will break a chained `.filter()` after it — guard the whole\nchain or supply the `?? []` fallback.\n",{"id":93,"difficulty":14,"q":94,"a":95},"double-question-mark-with-function-call","Does the right-hand side of ?? always evaluate?","No — `??` **short-circuits**. The right operand evaluates **only** when the left\nis `null`\u002F`undefined`. So an expensive default or a function call on the right is\nskipped when the left has a value.\n\n```js\nlet computed = 0\nconst v = 'cached' ?? expensive()    \u002F\u002F expensive() never runs\nfunction expensive() { computed++; return 'x' }\nconsole.log(computed)                \u002F\u002F 0  skipped\n```\n\nThis makes `value ?? buildDefault()` cheap in the common case. Pitfall: relying\non the right side's side effects is a bug, since it may never execute.\n",{"id":97,"difficulty":73,"q":98,"a":99},"chaining-after-optional-call","How does a ?. short-circuit affect the rest of a long chain?","Once any `?.` short-circuits, the **entire remaining chain** — further property\naccesses, calls, and index lookups — is skipped, and the whole expression is\n`undefined`. The short-circuit \"infects\" everything to its right.\n\n```js\nconst obj = { a: null }\nconsole.log(obj.a?.b.c.d())          \u002F\u002F undefined  b.c.d() all skipped\n```\n\nYou don't need `?.` on every link **after** the one that may be nullish — the\nfirst short-circuit covers the rest. Pitfall: but each *independent* uncertain\nlink still needs its own `?.`; the short-circuit only protects links **downstream**\nof where it fired.\n",{"id":101,"difficulty":24,"q":102,"a":103},"nullish-with-numbers","Why is ?? recommended for numeric defaults?","Because `0` is a valid number but **falsy**, `||` would wrongly replace it.\n`??` only replaces `null`\u002F`undefined`, so a real `0` survives.\n\n```js\nconst volume = settings.volume ?? 100   \u002F\u002F volume of 0 stays 0\n\u002F\u002F const bad = settings.volume || 100   \u002F\u002F 0 becomes 100 — muted unmute!\n```\n\nSame reasoning applies to any field where `0`, `''`, or `false` are meaningful.\nPitfall: a \"default to 100\" written with `||` silently breaks the legitimate-zero\ncase — a classic slider\u002Fquantity bug.\n",{"id":105,"difficulty":73,"q":106,"a":107},"optional-chaining-with-this","Does optional chaining preserve the this binding in a method call?","Yes. `obj?.method()` keeps `this` bound to `obj`, exactly like a normal method\ncall — the `?.` only adds the nullish guard, it doesn't change the call's\nreceiver.\n\n```js\nconst counter = {\n  n: 5,\n  get() { return this.n }\n}\nconsole.log(counter?.get())          \u002F\u002F 5  this is still counter\n```\n\nThe short-circuit happens before the call, so `this` is irrelevant when it fires.\nPitfall: extracting the method first (`const g = counter?.get; g()`) **loses**\n`this`, just like without `?.` — optional chaining doesn't bind methods.\n",{"id":109,"difficulty":14,"q":110,"a":111},"nullish-chaining-multiple","How do you chain multiple ?? operators?","`a ?? b ?? c` returns the **first non-nullish** value left to right. It's a clean\nway to express a fallback priority list.\n\n```js\nconst value = userSetting ?? cookieSetting ?? defaultSetting ?? 'fallback'\nconsole.log(null ?? undefined ?? 0)  \u002F\u002F 0  first non-nullish wins (0 counts)\n```\n\nEach `??` short-circuits, so evaluation stops at the first real value. Pitfall:\nthis is valid (chaining `??` with `??` is fine), but mixing in a `||` mid-chain\nwithout parentheses is a syntax error.\n",{"id":113,"difficulty":73,"q":114,"a":115},"optional-delete","Can you use optional chaining with the delete operator?","Yes — `delete obj?.prop` deletes the property if `obj` exists, and is a **no-op**\n(returning `true`) if `obj` is `null`\u002F`undefined`. It's one of the few non-read\ncontexts `?.` allows.\n\n```js\nconst obj = { a: 1 }\ndelete obj?.a                        \u002F\u002F deletes a\nconst nothing = null\ndelete nothing?.x                    \u002F\u002F no-op, no throw\n```\n\nAssignment is still forbidden, but deletion is permitted because it short-circuits\ncleanly. Pitfall: it's an uncommon form, so reviewers may not realize the delete\nis conditionally skipped when the object is nullish.\n",{"id":117,"difficulty":14,"q":118,"a":119},"nullish-assignment-lazy","How is ??= useful for lazy initialization or caching?","Because `??=` only assigns (and only evaluates the right side) when the property is\nnullish, it's perfect for \"compute once and cache\" — subsequent calls skip the\nwork.\n\n```js\nconst cache = {}\nfunction get(key) {\n  return cache[key] ??= expensiveLookup(key)  \u002F\u002F computed once per key\n}\n```\n\nOn the first call `cache[key]` is `undefined`, so the lookup runs and stores;\nlater calls return the cached value without recomputing. Pitfall: if\n`expensiveLookup` can legitimately return `null`\u002F`undefined`, it's treated as\n\"not cached\" and re-runs every time.\n",{"id":121,"difficulty":14,"q":122,"a":123},"optional-chaining-falsy-confusion","Does ?. return undefined or the actual value when the chain succeeds?","When the chain **succeeds**, `?.` returns the real value — it does **not** convert\nanything. It only injects `undefined` when it actually short-circuits on a\nnullish link.\n\n```js\nconst obj = { a: 0, b: false }\nconsole.log(obj?.a)                  \u002F\u002F 0      real value\nconsole.log(obj?.b)                  \u002F\u002F false  real value, not undefined\nconsole.log(obj?.missing)            \u002F\u002F undefined  (short-circuit)\n```\n\nSo a result of `undefined` could mean \"short-circuited\" **or** \"property is\ngenuinely `undefined`.\" Pitfall: you can't distinguish those two cases from the\nresult alone — use `in` or `hasOwnProperty` if the difference matters.\n",{"id":125,"difficulty":14,"q":126,"a":127},"nullish-in-jsx-or-template","Why is ?? safer than || when rendering values in UI?","In templating\u002FJSX, falsy-but-valid values like `0` or `''` should render. `||`\nwould replace them with the fallback, hiding real data; `??` keeps them.\n\n```js\n\u002F\u002F showing a like count:\nconst display = post.likes ?? 'N\u002FA'  \u002F\u002F 0 renders as 0\n\u002F\u002F const bad = post.likes || 'N\u002FA'   \u002F\u002F 0 likes shows 'N\u002FA'\n```\n\nSame for displaying an empty search query or a `false` toggle label. Pitfall:\n`||` in a render path is a frequent source of \"why does zero show as N\u002FA?\" bug\nreports.\n",{"id":129,"difficulty":14,"q":130,"a":131},"optional-chaining-performance","Does optional chaining have meaningful performance cost?","Negligibly. `?.` compiles to a simple `null`\u002F`undefined` check before each\naccess — a tiny conditional. It's far cheaper than the bugs and verbose guards it\nreplaces.\n\n```js\n\u002F\u002F these are essentially equivalent in cost:\nconst a = obj && obj.prop\nconst b = obj?.prop                  \u002F\u002F same check, cleaner\n```\n\nThe \"cost\" worth watching is **semantic**, not CPU — readability and bug-hiding.\nPitfall: don't avoid `?.` for imagined perf reasons; the real concern is using it\nwhere a value should never be nullish (see over-use).\n",{"id":133,"difficulty":73,"q":134,"a":135},"combining-optional-call-and-nullish","How do you safely invoke an optional callback and provide a result default?","Combine `?.()` (skip the call if the function is absent) with `??` (default the\nresult if the call was skipped or returned nullish).\n\n```js\nfunction process(data, transform) {\n  return transform?.(data) ?? data   \u002F\u002F use transform if given, else raw data\n}\nprocess(5)                           \u002F\u002F 5  — no transform, falls back\nprocess(5, x => x * 2)               \u002F\u002F 10 — transform applied\n```\n\n`transform?.(data)` is `undefined` when no callback is passed, and `?? data`\nsupplies the fallback. Pitfall: if `transform` legitimately returns `0`\u002F`''`,\n`??` keeps it (good), but `|| data` would wrongly discard those.\n",{"id":137,"difficulty":14,"q":138,"a":139},"nullish-coalescing-with-assignment-target","Why prefer config.x ??= default over config.x = config.x ?? default?","They're equivalent in result, but `??=` is shorter and, crucially,\n**short-circuits the assignment**: when `config.x` already has a value, no write\nhappens — avoiding spurious setter calls or proxy traps.\n\n```js\n\u002F\u002F verbose:\nconfig.x = config.x ?? compute()\n\u002F\u002F concise + skips the write when x exists:\nconfig.x ??= compute()               \u002F\u002F\n```\n\nFor plain objects the difference is cosmetic; for objects with setters or\nreactive frameworks it avoids unnecessary side effects. Pitfall: on a getter-only\n(read-only) property, `??=` still attempts the write when nullish and throws in\nstrict mode.\n",{"id":141,"difficulty":73,"q":142,"a":143},"optional-chaining-with-bracket-call","How do you combine dynamic key access and optional method calls in one chain?","You can mix `?.[key]` and `?.()` freely in a single chain; each `?.` guards its\nown link, and the first nullish one short-circuits the rest.\n\n```js\nconst handlers = { onSave: () => 'saved' }\nconst name = 'onSave'\nconsole.log(handlers?.[name]?.())    \u002F\u002F 'saved'\nconsole.log(handlers?.['onDelete']?.())  \u002F\u002F undefined  missing handler, no throw\n```\n\nThis pattern safely dispatches to a dynamically-named handler that may not exist.\nPitfall: `handlers[name]?.()` (no `?.` before `[name]`) still throws if\n`handlers` itself is nullish — guard the root too.\n",null,{"description":11},"JavaScript optional chaining and nullish coalescing interview questions — the ?. operator on properties, methods, and calls, ?? vs ||, logical assignment operators ??= ||= &&=, short-circuiting, and precedence pitfalls.","javascript\u002Fmodern\u002Foptional-chaining-nullish","Optional Chaining & Nullish Coalescing","Modern JavaScript (ES6+)","modern","2026-06-18","WX3Bq31uUWq16_jGkIHCQ3CHmeRYaov98DiBBBbqeLY",[154,158,159,163],{"subtopic":155,"path":156,"order":157},"Destructuring, Spread & Rest","\u002Fjavascript\u002Fmodern\u002Fdestructuring-spread-rest",1,{"subtopic":148,"path":20,"order":12},{"subtopic":160,"path":161,"order":162},"Template Literals & Tagged Templates","\u002Fjavascript\u002Fmodern\u002Ftemplate-literals",3,{"subtopic":164,"path":165,"order":166},"Symbols","\u002Fjavascript\u002Fmodern\u002Fsymbols",4,{"path":168,"title":169},"\u002Fblog\u002Fjavascript-optional-chaining-nullish-coalescing","Optional Chaining & Nullish Coalescing in JavaScript — Safe Access Done Right",1781808676010]