??=, ||= and &&=: The Assignment Operators Nobody Told You About
Every JavaScript codebase is littered with "assign if missing" statements. Since ES2021 they're single operators, and picking the right one prevents a classic bug in the process.
options.timeout ??= 5000; // assign only if null/undefined
cache[key] ||= computeValue(); // assign if falsy
user.isAdmin &&= stillValid(); // reassign only if currently truthy
??= is the default-setter you want
The old idiom x = x || fallback has a hole: it clobbers every falsy value. Pass 0, empty string or false on purpose, and the fallback stomps it:
settings.retries = settings.retries || 3; // retries: 0 becomes 3. Bug.
settings.retries ??= 3; // 0 survives; only null/undefined get 3
??= only assigns when the value is null or undefined - "not provided" rather than "provided but falsy". For config objects, function options and API defaults, that's almost always the semantics you meant.
They short-circuit the whole assignment
A subtlety that makes these more than sugar: if the condition fails, the right side never evaluates and no assignment happens at all:
// computeExpensive() doesn't run if cache[key] already set
cache[key] ??= computeExpensive();
// No setter call, no Proxy trap, no property write when skipped
observedObject.field ??= expensive();
With x = x ?? y, the write happens even when x keeps its value - which matters with setters, Proxies (like change trackers) and anything watching mutations. The ??= form genuinely skips the write.
Where ||= and &&= earn their spots
// ||= - when falsy really does mean "replace it"
draft.title ||= 'Untitled'; // empty string should become Untitled
// &&= - update a value only if it's currently set
session.user &&= refreshUser(session.user); // stays null if logged out
The lazy-initialization pattern is my favorite everyday use, especially with the grouping trick:
(groups[type] ??= []).push(item); // create-or-get the bucket, then push
One line that used to be three - though if you're grouping whole arrays, Object.groupBy does it natively now.
Support is everywhere post-2021 (Node 15+). Small feature, but the ||-vs-?? distinction it forces you to think about has probably fixed more bugs than the syntax saved keystrokes.
Full-stack web developer sharing practical tutorials and building tools that ship.
Got something on your mind?
My inbox is open - no forms disappearing into the void here.
- Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
- Hire me for a project Have something custom in mind? Let's talk scope and timelines.
- Product support Bought something here? I'll help you get it running.
I usually reply within 1-2 business days.