Logical assignment operators in JavaScript: small syntax, big wins
In day-to-day JavaScript, we often check a variable before assigning it a new value, and it gets repetitive with component props, global configs, and state objects. Logical assignment operators (ES2021) shorten that without changing the logic.
What are logical assignment operators?
Logical assignment operators combine a logical operator (||, &&, or ??) with assignment (=) to create a shorthand form. These operators also short-circuit like regular logical expressions, meaning the right-hand side is only evaluated if the left-hand side fails the logical test (i.e., is falsy, truthy, or nullish).
// ❌ SyntaxError:
user?.settings ||= {};
Optional chaining returns the result of a property access, not a reference to the property itself. Since assignment targets must be references (i.e., a variable or object property), this isn’t valid JavaScript.
Logical OR assignment (||=)
Assign if falsy:
user.theme ||= 'light';
Equivalent to:
if (!user.theme) {
user.theme = 'light';
}
This is useful for setting a default if a value hasn’t been initialized. But it overwrites values like 0, '', or false, which might be intentionally set.
Logical AND assignment (&&=)
Assign if truthy:
user.isLoggedIn &&= checkPermissions(user);
Equivalent to:
if (user.isLoggedIn) {
user.isLoggedIn = checkPermissions(user);
}
This is helpful for conditionally updating a value based on an existing truthy value.
let isEnabled = true;
isEnabled &&= false;
console.log(isEnabled); // false
The original value (true) acts as a gate, but it’s the result of checkPermissions (or any right-hand expression) that becomes the new value. &&= doesn’t preserve the old value, it replaces it.
Nullish coalescing assignment (??=)
Assign if nullish (null or undefined):
settings.timeout ??= 3000;
Equivalent to:
if (settings.timeout === null || settings.timeout === undefined) {
settings.timeout = 3000;
}
Use this when you want to assign defaults only if the value is truly missing, not just falsy. Unlike ||=, it preserves valid values like 0, false, and ''.
Where they help
They save a lot of repetitive checks, especially with mutable state:
Defaulting component props
props.showHelpText ??= true;
Avoiding overwrites in global state or config
config.apiBase ||= '/api/v1';
Preventing accidental null/undefined assignments
formData.username &&= formData.username.trim();
But keep in mind
-
||=assigns when the left-hand side is falsy, which includes0,'', andfalse, values you might want to keep.let count = 0; count ||= 10; // overwrites count with 10, be careful! - Use
??=when you want to guard specifically againstnullorundefined, and preserve valid falsy values. -
Right-hand expressions are only evaluated if needed, preserving performance and avoiding side effects.
config.apiKey ||= fetchApiKey(); // fetchApiKey() only runs if apiKey is falsy
Example with a side effect
let calls = 0;
let obj = { val: 0 };
obj.val ||= ++calls;
console.log(obj.val); // 1, because 0 is falsy
obj.val ||= ++calls;
console.log(obj.val); // still 1, second increment never runs
Since obj.val is initially 0 (falsy), ++calls is evaluated and assigned. On the second line, obj.val is now 1 (truthy), so ++calls is skipped. The value of calls remains 1.
Browser support
Logical assignment operators are supported in all modern environments:
- ✅ Chrome 85+, Firefox 79+, Safari 14+, Edge 85+
- ✅ Node.js 15+
- ❌ Not supported in Internet Explorer
If you’re targeting older environments, use a transpiler like @babel/preset-env with ES2021 settings.
Now you’re ready!
Logical assignment operators are a small addition, but they save a lot of repetitive if checks, especially with props, state, API defaults, and form input.
If you’re already comfortable using ||, &&, and ??, you’re ready for ||=, &&=, and ??=. It’s just muscle memory from here.