---
title: 'Truthy and Falsy Values'
source: 'https://academia.sh/en/courses/javascript-fundamentals/truthy-and-falsy-values'
course: 'JavaScript Fundamentals'
language: en
updated: '2026-08-23T07:00:59+00:00'
license: 'CC BY-SA 4.0'
---

# Truthy and Falsy Values

The to-boolean conversion procedure, the eight values counted as false, logical operators returning a value, nullish coalescing, and optional chaining.

The previous two lessons defined two coercion procedures: converting to number and to
string. The third, converting to boolean, is the foundation of conditional constructs and
answers a question deferred across two lessons: why was the value `0` mistaken for
missing data?

The procedure itself is short — there is no page of rules, there is a list of eight
values. The real subtlety is not in the list, it is in how logical operators use that
list.

## The Eight Values Counted as False

The to-boolean conversion procedure is defined by a list: the following eight values are
**counted as false (falsy)**, every other value is counted as true.

```js
const falsyValues = [
  ["false", false],
  ["0", 0],
  ["-0", -0],
  ["0n", 0n],
  ['""', ""],
  ["null", null],
  ["undefined", undefined],
  ["NaN", NaN],
];

for (const [label, value] of falsyValues) {
  console.log(label.padEnd(10), Boolean(value));
}
```

```
false      false
0          false
-0         false
0n         false
""         false
null       false
undefined  false
NaN        false
```

The list is closed: no value not on it is counted as false. This is a more useful rule
than memorizing the list, because it resolves counterintuitive examples directly:

```js
console.log(Boolean("0"), Boolean("false"), Boolean(" "));
console.log(Boolean([]), Boolean({}));
console.log(Boolean(-1), Boolean(Infinity));
```

```
true true true
true true
true true
```

Every non-empty string is counted as true — regardless of its content. The texts `"0"`
and `"false"` fall under this rule too; they are not converted to number or boolean. An
empty array and an empty object are also counted as true: objects are not on the list, so
all of them are true. Every number besides zero, including negatives and infinity, is
counted as true.

One point deserves attention: `Boolean([])` gives true, while the previous lesson's
`[] == false` comparison gave true too. There is no contradiction — two different
procedures are running. Loose equality converts the array to a primitive value, then to a
number; converting to boolean never looks inside the object at all. The same value giving
a different result in two different contexts makes it necessary to know which procedure
is being called.

## Logical Operators Do Not Return a Boolean

The `&&` and `||` operators, despite their names, do not produce `true` or `false`. They
return **one of the operands**:

```js
console.log(0 || "fallback");
console.log("A1" || "fallback");
console.log(0 && "never");
console.log("A1" && 21.5);
```

```
fallback
A1
0
21.5
```

The rule is this. The `||` operator evaluates the left operand; if it is counted as true,
it returns it, otherwise it returns the right operand. The `&&` operator evaluates the
left operand; if it is counted as false, it returns it, otherwise it returns the right
operand.

The right operand is evaluated only when needed. This is the short-circuit evaluation
defined in the Operators and Expressions lesson of the Programming Fundamentals course. In
the third line, `"never"` was never evaluated at all.

If the result needs to be forced to boolean type, the conversion is written explicitly.
Because conditional constructs already convert to boolean, this is usually unnecessary.

## The Default-Value Trap

The `||` operator's most common use is putting a fallback in place of a missing value.
This use breaks down when a falsy value is valid data:

```js
const records = [
  { station: "A1", temperature: 21.5 },
  { station: "A2", temperature: 0 },
  { station: "B1" },
];

for (const record of records) {
  const viaOr = record.temperature || -273.15;
  const viaNullish = record.temperature ?? -273.15;
  console.log(record.station, "|| ->", viaOr, " ?? ->", viaNullish);
}
```

```
A1 || -> 21.5  ?? -> 21.5
A2 || -> -273.15  ?? -> 0
B1 || -> -273.15  ?? -> -273.15
```

The middle line is the answer to the question left open across two lessons. Station
`A2`'s temperature is `0`; this is a valid measurement and it is present in the record.
Still, the `||` operator counted it as false and moved to the fallback value. The
measurement turned into absolute-zero temperature.

In the bottom line's `B1` record, the temperature field truly does not exist; the value
of `record.temperature` is `undefined`, and moving to the fallback is correct there. The
two lines produced the same result, but only one of them was the intended behavior — the
`||` operator cannot distinguish "there is no value" from "the value is zero."

The `??` operator — **nullish coalescing** — moves to the right operand only for `null`
and `undefined` values:

```js
console.log(0 || "fallback");
console.log(0 ?? "fallback");
console.log("" || "fallback");
console.log("" ?? "fallback");
console.log(null ?? "fallback");
```

```
fallback
0
fallback

fallback
```

The fourth line looking empty is because the `??` operator counts an empty string as a
valid value and returns it. The second line, on the other hand, preserved the value `0`.

The selection rule is clear: **if the meaning "value was never given" is wanted, use
`??`; if the meaning "value is counted as false" is wanted, use `||`.** In measurement
data, zero, an empty string, and `false` are most often valid values; this is why default
assignments are written with `??`.

## Optional Chaining

The third operator of the same family shortens the absence check while accessing nested
fields:

```js
const record = { station: "A1", location: { elevation: 120 } };
const missing = { station: "B1" };
console.log(record.location?.elevation);
console.log(missing.location?.elevation);
console.log(missing.location?.elevation ?? 0);
```

```
120
undefined
0
```

The `?.` operator breaks the chain and returns `undefined` if the value to its left is
`null` or `undefined`; otherwise it continues the access. The check's criterion is the
same as `??` — not values counted as false, only the two absence values.

The same access without the operator throws an error:

```js
const missing = { station: "B1" };
try {
  console.log(missing.location.elevation);
} catch (error) {
  console.log(error.name + ": " + error.message);
}
```

```
TypeError: Cannot read properties of undefined (reading 'elevation')
```

The Ways to Run Code lesson showed how to read this message: the problem is not in the
`elevation` field, it is that the value of `missing.location` is `undefined`.

Optional chaining should be used carefully. It is the right tool if a field being absent
is an expected situation; if it is an unexpected situation, it suppresses the error and
carries the problem forward. The difference lies in the data's contract, not in the
syntax.

## Application to the Measurement Script

The shortest use of truthy and falsy values is a filtering operation:

```js
const fields = ["21.5", "", "0", "abc", null];
const filled = fields.filter(Boolean);
console.log(filled);
```

```
[ '21.5', '0', 'abc' ]
```

The empty string and `null` were eliminated; the text `"0"` was preserved, because it is
a non-empty string. This is exactly the intended behavior: what is being filtered here is
raw text, not a numeric value.

Applying the same filter to numeric values loses data:

```js
const measurements = [21.5, 0, NaN, 19.75];
console.log(measurements.filter(Boolean));
console.log(measurements.filter((value) => !Number.isNaN(value)));
```

```
[ 21.5, 19.75 ]
[ 21.5, 0, 19.75 ]
```

The first filter dropped a valid zero measurement. The second dropped only what was
truly invalid. The rule is that truthy and falsy values are not a general validity
criterion: what counts as valid depends on the data's meaning and has to be written
explicitly.

## Summary

- The to-boolean conversion procedure counts eight values as false: `false`, `0`, `-0`,
  `0n`, an empty string, `null`, `undefined`, `NaN`. Every other value is counted as
  true.
- An empty array, an empty object, and strings like `"0"` are counted as true; objects
  are not on the list.
- `&&` and `||` return one of the operands, not a boolean, and evaluate the right operand
  only when needed.
- `||` moves to the fallback for all eight values; `??` moves only for `null` and
  `undefined`. Default assignments in measurement data are written with `??`.
- `?.` breaks the chain only for `null` and `undefined`; it should not be used to hide an
  unexpected absence.

## Next Step

The value model is complete: what types exist, how they convert, how they are compared,
and how they are evaluated in a condition. Next is building program flow with these
values. The next topic will begin with conditional selection: `if` chains, the ternary
operator, and which equality the `switch` statement uses for comparison — one of the
three operators from this lesson.
