When working with JavaScript, we often need to set default configurations and allow users to override certain values. A common but flawed approach is using the logical OR (||) operator for defaults, which can lead to unexpected behavior. This article explains why || is problematic for object merging and how to correctly override defaults using the ES6 spread operator (...).
1. The Problem: Why || Falls Short
Consider this typical pattern:
const enabledEngines = this.settings?.enabledEngines || {
baidu: true,
google: true,
bing: true,
so: true,
sogou: true
};
Key Issues with ||:
-
||Only Checks for Falsy Values, Failing to Overridefalse- If
this.settings?.enabledEnginesis{ google: false }, the||operator won’t apply the fallback (since an object is truthy), incorrectly keepinggoogle: true. - The fallback only triggers if the left side is
undefined/null.
- If
-
No Partial Overrides
- If a user only wants to disable one engine (e.g.,
{ bing: false }),||forces a full replacement, discarding other defaults.
- If a user only wants to disable one engine (e.g.,
2. The Solution: Object Spread Operator (...)
The correct approach is to let user settings override defaults without discarding the entire object. The ES6 spread operator (...) solves this elegantly:
const enabledEngines = {
baidu: true,
google: true,
bing: true,
so: true,
sogou: true,
...this.settings?.enabledEngines // User settings override defaults
};
Why This Works:
- Correctly Handles
falseOverrides- If the user passes
{ google: false },googleis properly disabled while other defaults remain.
- If the user passes
- Supports Partial Updates
- Users only need to specify changes; unspecified keys keep their defaults.
- Safer Than
||- Even an empty object
{}won’t trigger an unwanted fallback.
- Even an empty object
3. Real-World Examples
Case 1: User Disables Google
const userSettings = { google: false };
// Wrong (||)
const badResult = userSettings || { google: true, bing: true };
// => { google: false } ( bing is lost!)
// Right (...)
const goodResult = { google: true, bing: true, ...userSettings };
// => { google: false, bing: true } (Correct!)
Case 2: No User Settings Provided
const userSettings = undefined;
// Wrong (||)
const badResult = userSettings || { google: true };
// => { google: true } (Works but inflexible)
// Right (...)
const goodResult = { google: true, ...userSettings };
// => { google: true } (Same outcome, but consistent)
4. When Is || Acceptable?
While || isn’t ideal for objects, it’s still useful for:
- Primitive defaults (e.g.,
string,number,boolean)const limit = userLimit || 10; // Fails if userLimit is 0! - Full replacements (not merging)
const config = userConfig || defaultConfig; // Replaces entirely
For object merging, always prefer ....