Lập trình · 25/09/2026

JavaScript ?? and ||: Choose Defaults Without Losing Zero

A user chooses zero retries, yet the application still retries three times. The expression retries || 3 may be the culprit: it treats zero as a reason to use the fallback. When values such as zero or false are meaningful, defaults must preserve their business meaning.

JavaScript ?? và ||: Chọn giá trị mặc định mà không làm mất số 0

A user chooses zero retries, yet the application still retries three times. The expression retries || 3 may be the culprit: it treats zero as a reason to use the fallback. When values such as zero or false are meaningful, defaults must preserve their business meaning.

1. Missing differs from falsy

The MDN ?? reference explains that the right operand is used only for null or undefined. By contrast, || falls back for any falsy value, including zero, false and an empty string.

const settings = { retries: 0, enabled: false };

console.log(settings.retries || 3); // 3
console.log(settings.retries ?? 3); // 0
console.log(settings.enabled ?? true); // false

Comments show expected results. This scenario defines zero as no retries and false as deliberately disabled. If those values are invalid for your product, validate them explicitly instead of relying on fallback operators.

2. Define policy per field

ValuePolicy question
Zero retriesIs disabling retries a valid choice?
An empty labelDoes it mean no label or unfinished input?
nullIs data missing or deliberately cleared?

Do not mechanically replace every || with ??. Some fields intentionally fall back for empty strings; others must preserve them. Document the decision before changing code.

3. Defaults are not type validation

function normalizeRetries(value) {
  const retries = value ?? 3;
  if (!Number.isInteger(retries) || retries < 0 || retries > 10) {
    throw new TypeError('Expected an integer from 0 to 10');
  }
  return retries;
}

This illustrative policy defaults missing values to three and requires supplied values to be integers from zero to ten. It rejects "3", false and NaN. Ten is a product-specific example, not a universal limit.

Avoid arbitrary coercion merely to pass validation. Form fields or environment variables may contain strings and require an explicit parsing step first.

4. Keep expressions readable

Do not mix ?? directly with || or && without parentheses. Parentheses fix syntax, not policy correctness. For several fallback layers, introduce descriptive variables so reviewers can understand the priority.

The right side of ?? runs only when needed. If it calls a function, do not rely on that function's side effects for mandatory work.

5. Test checklist

  • Test undefined, null, zero, false and an empty string separately.
  • Test correctly typed values outside the allowed range.
  • Check string input from APIs or forms.
  • Ensure defaults preserve deliberate disabled settings.
  • Add regression tests for missing-versus-zero mistakes.

The correct operator expresses the intended policy. Use ?? when only null and undefined require a fallback, and keep validation as a separate step.

Discussion

Comments 0

Sign in to comment

You need an account to join the discussion and reply to other readers.

Sign inRegister

No comments yet. Be the first to share your thoughts.