skip to content

Truthy, Falsy, and ToBoolean

The falsy list is short enough to memorize, but interviewers care that you know || and && return an operand rather than a boolean, and why ?? was added so that 0 and the empty string stop being swallowed by defaults.

part ofJavaScriptoverview, primer and where to startread it →
on this pageshow

questions

4

In JavaScript, which values are falsy — that is, which convert to false when used as an `if` condition — and which commonly-assumed-falsy values are actually truthy?

level: juniorimportance: must knowfreq 85%

answer

  1. a short closed list, everything else true
  2. zeros, empties, and the two nothings
  3. '0' and [] are on the true side
  4. objects are never inspected, only classified
  5. eight values: false, 0, -0, 0n, '', null, undefined, NaN

basics

~20 s

JavaScript has a fixed falsy list: false, 0, -0, 0n, the empty string, null, undefined, and NaN. Every other value is truthy — including '0', 'false', the empty array, the empty object, and every function.

solid answer

~50 s

JavaScript defines a small, fixed falsy set and treats everything else as truthy. The falsy values are `false`, the numeric zeros `0`, `-0` and `0n`, the empty string `''`, `null`, `undefined`, and `NaN`. Any value not on that list converts to `true` under the spec's abstract ToBoolean operation, which is what `if`, `while`, `!`, the conditional operator and the logical operators all invoke. The ones that trip people up are the values that *look* empty but are not: the string `'0'`, the string `'false'`, an empty array `[]`, an empty object `{}`, and any function — every object is truthy regardless of its contents. Browsers keep one documented legacy exception, `document.all`, falsy for web compatibility. In practice I memorise the list and use an explicit check whenever the value can legitimately be `0` or `''`.

code

javascript · 6 lines
javascript
const falsy = [false, 0, -0, 0n, '', null, undefined, NaN];
const surprising = ['0', 'false', ' ', [], {}, function () {}, Infinity];

console.log(falsy.every((v) => !v));            // true  — all eight are falsy
console.log(surprising.every((v) => Boolean(v))); // true — all of these are truthy
console.log(Boolean([]), Boolean({}), Boolean('0')); // true true true

go deeper

for a junior

Be able to recite the eight falsy values on demand and state plainly that everything else, including '0', [] and {}, is truthy. Interviewers use this as a fast screen.

for a middle

Explain that ToBoolean is a total conversion applied by if, !, ?:, && and ||, and that it classifies objects as truthy without ever inspecting them or calling conversion hooks.

for a senior

Show the production instinct: identify the code paths where 0, '' or false are legal domain values and replace bare truthiness with an explicit comparison before the bug reaches a user.

for a principal

Frame it as an API-design constraint — a parameter or config field whose valid range includes a falsy value forces every consumer into explicit checks, so prefer domains where 'absent' and 'zero' are not both representable.

## What "truthy" actually means JavaScript never asks whether a value *is* a boolean when you write a condition. It applies an internal conversion the specification calls **ToBoolean** — an abstract operation, not a function you can call directly, though `Boolean(x)` and `!!x` expose it exactly. ToBoolean is total: it accepts any value and returns `true` or `false`, and it never throws, never calls user code, and never looks at an object's contents. The rule is defined by a short table of values that map to `false`. Everything else maps to `true`. "Falsy" and "truthy" are just the informal names for those two groups. ## The falsy set There are eight falsy values in the language: - `false` — the boolean itself - `0` — positive zero - `-0` — negative zero (a distinct numeric value, but equally falsy) - `0n` — the BigInt zero - `''` — the empty string (identical for `""` and an empty template literal) - `null` - `undefined` - `NaN` That is the whole list. It is worth memorising verbatim, because interviewers ask for it directly and because every truthiness bug you will ever debug comes from a value on this list arriving where you expected "nothing". ```js for (const v of [false, 0, -0, 0n, '', null, undefined, NaN]) { console.log(Boolean(v)); // false, eight times } ``` ## Everything else is truthy — including the empty-looking things Because the falsy list is closed, the interesting half of the answer is what *isn't* on it: ```js Boolean('0'); // true — a non-empty string Boolean('false'); // true — still just characters Boolean(' '); // true — a space is a character Boolean([]); // true — an object Boolean({}); // true — an object Boolean(function () {}); // true — functions are objects Boolean(Infinity); // true Boolean(-1); // true — only zero is falsy, not "negative" ``` The single most useful generalisation: **every object is truthy**, no matter what it holds. An empty array, an empty object, an empty `Map`, and even a wrapper object like `new Boolean(false)` are all truthy, because ToBoolean stops at "is this an object?" and answers `true` without inspecting anything inside. It does not call `valueOf`, `toString`, or any conversion hook. That is why `if (list)` can never tell you whether a list has elements. One exception exists, and it is a host quirk rather than a language rule: in browsers, `document.all` is specified to be falsy, a deliberate web-compatibility hack so that old feature-detection code takes the modern branch. It is the only falsy object you will meet, and no other value behaves that way. ## Where ToBoolean is invoked The same conversion runs in more places than people realise: - `if (x)`, `while (x)`, `do…while (x)`, the middle clause of `for (;x;)` - `!x` (and therefore `!!x`) - the condition of the conditional operator `x ? a : b` - the left operand test of `&&` and `||` - `Boolean(x)` called as a function - `Array.prototype.filter(Boolean)`, which simply passes each element through it Notably, `??` does **not** use ToBoolean — it tests only for `null` and `undefined` — and `if (x)` is therefore a strictly wider test than "is it missing". ## The bugs this causes The classic failure is treating truthiness as a presence check for a value whose valid domain includes a falsy member: ```js function render(count) { if (!count) return 'nothing to show'; // wrong when count === 0 return `${count} items`; } ``` Zero is a perfectly good count, an empty string is a perfectly good name, and `false` is a perfectly good setting — but all three take the "missing" branch. The fix is to say what you actually mean: `count === undefined`, `count == null` (which matches both `null` and `undefined`), or `Number.isFinite(count)`. Truthiness is a convenience for the common case where every falsy value really is invalid; it is not a substitute for a domain check. The mirror-image bug is assuming an empty container is falsy: `if (results)` is always true for an array, so emptiness needs `results.length === 0`. ## How to talk about it A strong answer recites the eight values without hesitation, adds the generalisation that everything else — objects above all — is truthy, and then immediately names the practical consequence: truthiness conflates "absent" with "zero, empty, or false", so any code path where `0` or `''` is legal needs an explicit comparison rather than a bare `if`.

  • How do you convert a value to a real boolean, and does the technique change the result?
    `Boolean(x)` and `!!x` are the two idioms, and they produce identical results because both run the same ToBoolean operation — `!!` is just double negation. `Boolean` called as a function never constructs anything; `new Boolean(x)` does, and that wrapper object is always truthy, which is why the `new` form should never be used.
  • If every object is truthy, how should code test whether an array or object is empty?
    Ask the container directly. For arrays, `arr.length === 0`; for plain objects, `Object.keys(obj).length === 0`; for `Map` and `Set`, `.size === 0`. A bare `if (arr)` only tells you the variable holds something other than `null` or `undefined`, which is usually a separate question worth asking separately.
  • Is NaN the only falsy number, or are there others?
    There are four falsy numeric values: `0`, `-0`, `NaN`, and the BigInt `0n`. Every other number, including `Infinity`, `-Infinity`, and any negative number, is truthy — falsiness tracks zero-ness and not-a-number-ness, not sign or magnitude.

saying these in an interview costs you the question

  • Says an empty array or empty object is falsy
  • Thinks the string '0' or 'false' converts to false
  • Believes negative numbers are falsy because they are 'not positive'
  • Claims ToBoolean inspects an object's length or contents
  • Treats undefined and null as the only falsy values

context

open as a page

In JavaScript, what value do the `||` and `&&` operators produce — a boolean, or one of their operands? Walk through `'' || 'default'` and `0 && compute()`.

level: middleimportance: must knowfreq 70%

basics

~20 s

Both return one of their operands unchanged, never a coerced boolean. || returns the left operand if it is truthy, otherwise the right one; && returns the left operand if it is falsy, otherwise the right one. The unselected side is never evaluated.

open as a page

A service reads its settings with `const retries = options.retries || 3` and `const prefix = options.prefix || 'app'`. A caller passes `{ retries: 0, prefix: '' }` and both values are silently ignored. Explain the mechanism and how you would fix it.

level: seniorimportance: must knowfreq 60%

basics

~10 s

|| tests truthiness, and 0 and '' are falsy, so both caller values lose to the defaults. Use ??, which falls back only on null and undefined: options.retries ?? 3 keeps an explicit 0.

open as a page

Why is `if (items)` a broken way to check that a JavaScript array has elements, and what does ToBoolean do with objects in general?

level: middleimportance: should knowfreq 45%

basics

~20 s

ToBoolean classifies every object as true without inspecting it, so an empty array is truthy. if (items) only proves the variable is not null or undefined; emptiness needs items.length === 0, or .size for a Map or Set.

open as a page