How to Properly Merge Defaults with User Settings in JavaScript

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 ||:

  1. || Only Checks for Falsy Values, Failing to Override false

    • If this.settings?.enabledEngines is { google: false }, the || operator won’t apply the fallback (since an object is truthy), incorrectly keeping google: true.
    • The fallback only triggers if the left side is undefined/null.
  2. No Partial Overrides

    • If a user only wants to disable one engine (e.g., { bing: false }), || forces a full replacement, discarding other defaults.

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:

  1. Correctly Handles false Overrides
    • If the user passes { google: false }, google is properly disabled while other defaults remain.
  2. Supports Partial Updates
    • Users only need to specify changes; unspecified keys keep their defaults.
  3. Safer Than ||
    • Even an empty object {} won’t trigger an unwanted fallback.

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 ....

赞赏

微信赞赏支付宝赞赏

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注