ELSEIF
Your brief EB
183 stories from 71 feeds 32 clusters Refreshed 8 minutes ago next pull 13:20

JavaScript · Beginner

JavaScript truthy and falsy values without the guesswork

A complete, usable model of JavaScript boolean coercion—including the empty array trap, nullish values, NaN, and when to compare explicitly.

JavaScript conditions accept any value, not just a boolean. Before choosing a branch, the language converts that value to true or false. “Truthy” and “falsy” describe the result of that conversion; they are not extra data types.

if ('hello') {
  console.log('runs');
}

if (0) {
  console.log('does not run');
}

You can see the conversion directly with Boolean(value).

The complete falsy list

There are only eight falsy values in modern JavaScript:

Falsy value Meaning or common source
false The boolean false
0 Numeric zero
-0 Signed numeric zero
0n BigInt zero
'', "", or `` An empty string
null An intentional absence
undefined A missing or unassigned value
NaN An invalid numeric result

Every other value is truthy. Memorising the short falsy list is more reliable than trying to remember thousands of truthy possibilities.

const values = [false, 0, -0, 0n, '', null, undefined, NaN];
values.map(Boolean); // [false, false, false, false, false, false, false, false]

document.all is a historical browser oddity with falsy behaviour, but it should not be used in application logic.

Empty arrays and objects are truthy

The most common surprise is that an empty container is still an object, and objects are truthy:

Boolean([]); // true
Boolean({}); // true

if ([]) {
  console.log('this runs');
}

Test what you mean instead of testing the container itself:

const results = [];

if (results.length > 0) {
  showResults(results);
} else {
  showEmptyState();
}

For an object, you might test for a required property or inspect Object.keys(object).length, depending on the business rule.

The zero and empty-string problem

A truthiness check often accidentally treats a valid value as missing:

function showBalance(balance) {
  if (!balance) {
    return 'Balance unavailable';
  }

  return `$${balance}`;
}

showBalance(0); // "Balance unavailable"

Zero is a perfectly valid balance. If only null and undefined mean “missing,” use a nullish test:

function showBalance(balance) {
  if (balance == null) {
    return 'Balance unavailable';
  }

  return `$${balance}`;
}

The deliberate == null is one of the few useful loose comparisons: it matches both null and undefined, but not 0, false, or ''. If your codebase bans loose equality, write balance === null || balance === undefined.

|| and ?? answer different questions

The OR operator returns its right operand when the left operand is falsy. Nullish coalescing does so only for null or undefined:

const savedVolume = 0;

const withOr = savedVolume || 50;  // 50
const withNullish = savedVolume ?? 50; // 0

Use || when every falsy value should trigger the fallback. Use ?? when zero, false, and an empty string are valid data.

const displayName = user.nickname || 'Anonymous';
const retryCount = settings.retries ?? 3;

The first line treats an empty nickname as absent. The second preserves zero retries.

NaN needs its own test

NaN is falsy, but a broad falsy check loses the distinction between an invalid number and zero:

const quantity = Number('three');

if (Number.isNaN(quantity)) {
  console.log('Quantity must be numeric');
}

Prefer Number.isNaN() to the global isNaN(). The global function coerces its argument first and can label surprising inputs as numeric or non-numeric.

Boolean wrappers are objects

Avoid constructing booleans with new Boolean():

const misleading = new Boolean(false);

Boolean(misleading); // true
if (misleading) console.log('runs');

The wrapper contains false, but the wrapper itself is an object, so it is truthy. Use the primitive false or Boolean(value) without new.

When truthiness improves code

Truthiness reads well when the application meaning aligns with boolean coercion:

if (errorMessage) {
  showError(errorMessage);
}

If an empty error message genuinely means there is nothing to show, the concise condition is accurate.

Use an explicit comparison when distinct falsy values have different meanings:

if (responseCode === 0) {
  retryConnection();
} else if (responseCode === null) {
  waitForResponse();
}

The goal is not maximum explicitness. It is preserving the distinctions your program cares about.

See the complete language reference on MDN’s falsy value page.

How this was checked

Coercion examples and the comparison table were executed with Node.js 22.14.0 and checked against MDN's falsy-value reference.