Making decisions · Lesson 10 of 77 · concept

Truthiness and the falsy values

About 45 minutes.

By the end of this lesson you can

  • Say what JavaScript does when the condition of an if is not a boolean.
  • Recall the complete list of falsy values without looking it up.
  • Explain why an empty piece of text is falsy but an empty array is not.
  • Avoid the bug where a legitimate 0 is treated as missing.

A condition does not have to be true or false

Explanation

Every condition in the previous lesson produced a boolean, because every one of them was a comparison. But JavaScript lets you put ANY value in those round brackets: a number, a piece of text, nothing at all. It will not complain.

What it does instead is convert whatever you gave it into a boolean, using one fixed set of rules, and then use that. This conversion is what people mean by 'truthy' and 'falsy': a value is truthy if it converts to true in that position, falsy if it converts to false. Those are not extra types of value. Every value is truthy or falsy; it is a fact about how the value behaves in a condition, not about what it is.

You can see the conversion on its own by calling Boolean(value), which performs exactly the same conversion an if performs and hands you the result instead of branching on it. That makes it the tool for checking your understanding: if you are unsure whether something is truthy, log Boolean of it.

The list of falsy values is short - learn it and you know the rest

A mental model

There is no list of truthy values, because it would be infinite. There is a list of falsy ones, and it is short enough to memorise today: false, the number 0, the number -0, the BigInt 0n, the empty string "", null, undefined, and NaN. That is the whole list.

Everything else is truthy. Every other number, including negative numbers. Every non-empty piece of text - including the text "0" and the text "false", which trip people up because they look like falsy things while being ordinary non-empty text. Every array, including an empty one. Every object, including an empty one. Every function.

There is one historical exception you may read about: in web browsers, the document.all value is falsy despite being an object, a compatibility wart the standard was forced to keep. It does not exist outside a browser page and it will never come up in your own code. Mentioned only so that the word 'complete' above is honest.

MDN — Falsy (Glossary)

Check there: The table of falsy values: false, 0, -0, 0n, "", null, undefined, NaN, and the document.all exception.

Truthy does not mean 'has something in it'

A common mistake

The single most common wrong mental model is that truthy means full and falsy means empty. It nearly works for text, which is why it survives: "" is falsy, "hello" is truthy. Then it collapses.

An empty array is truthy. An empty object is truthy. The reason is that the falsy list contains no objects at all, and arrays and objects are objects - so the conversion never looks inside them. It does not count elements. It does not check keys. It sees 'an object' and answers true.

So 'if (items)' does not ask whether there are any items; it asks whether the variable holds anything other than one of the eight falsy values, which for an array is always. If you want to know whether an array has contents, ask for the thing you actually mean: items.length > 0. This is the rule to take from the whole lesson - test the property you care about, not the container.

The zero bug, and the empty-string bug

A common mistake

Here is the bug this lesson exists to prevent. You write 'if (count)' meaning 'if a count was supplied'. It works in testing, because your test data has counts like 3 and 7. Then a real count of 0 arrives - a perfectly good, correct, meaningful count - and because 0 is falsy your program reports it as missing. Zero items in stock is now indistinguishable from 'we have no idea how many items there are'.

The same trap has an empty-text version: 'if (name)' treats a genuinely empty name the same as a name that was never provided, and if that empty text was deliberate, you have quietly overruled the user.

The fix is always the same shape: say what you mean. If you are asking whether a value was supplied, compare against the thing that means 'not supplied': 'if (count !== undefined)'. If you are asking whether a number is positive, ask 'if (count > 0)'. If you are asking whether a value is a number at all, ask 'if (typeof count === "number")'. Each is longer than 'if (count)' by a few characters and none of them can be wrong in this way.

When leaning on truthiness is fine

Why it matters

None of this makes truthiness bad. It is used constantly in real code and reads well when the falsy values that could actually arrive are precisely the ones you want to reject.

The test to apply before writing 'if (value)' is a single question: which falsy values could this variable really hold, and do I want every one of them to take the false branch? If the variable is a flag that is only ever true or false, the answer is obviously yes and the short form is clearer. If the variable is a number that could legitimately be 0, or text that could legitimately be empty, the answer is no and you need an explicit test.

That question takes two seconds and it is the difference between idiomatic code and a bug that only appears at the boundary.

Recap

Recap

Any value can be a condition; JavaScript converts it with the same rules as Boolean(). Eight values are falsy: false, 0, -0, 0n, "", null, undefined, NaN. Everything else is truthy, including "0", "false", [] and {}. Truthiness never looks inside a container, so ask items.length > 0 rather than trusting the array itself, and never use bare truthiness for a number that might legitimately be 0.

Worked examples

Every output below was produced by actually running the code in the same sandbox your exercises run in — it is not a prediction.

Watching the conversion happen

Boolean(value) applies exactly the conversion an if applies. Run through these and check each answer against the falsy list before reading the output.

1console.log(Boolean(0), Boolean(""), Boolean(null), Boolean(undefined));2console.log(Boolean("0"), Boolean("false"), Boolean(" "), Boolean(-1));3console.log(Boolean([]), Boolean({}), Boolean(0.0001));
  • line 1

    Four of the eight falsy values. Note that undefined and null both convert to false, even though they are different values with different meanings.

  • line 2

    All truthy. "0" and "false" are non-empty text, and a single space is non-empty text too. -1 is a number that is not 0, so it is truthy - truthiness is not about being positive.

  • line 3

    An empty array and an empty object are both truthy: no object is on the falsy list, so the conversion never inspects their contents.

What it prints

false false false falsetrue true true truetrue true true

The zero bug, in eleven lines

This function looks reasonable and passes a casual test. Watch the second call: a real stock level of 0 is reported as if no information existed at all.

1function reportStock(count) {2  if (count) {3    console.log("We have " + count + " left.");4  } else {5    console.log("No count available.");6  }7}8 9reportStock(3);10reportStock(0);11reportStock(undefined);
  • line 2

    The intended meaning is 'if a count was supplied'. What it actually asks is 'if the count is not one of the eight falsy values' - and 0 is one of them.

  • line 10

    The bug. Zero is a genuine, correct stock level, and it lands in the branch meant for missing data.

  • line 11

    This call is the only one the else branch was written for, and its output is identical to the previous line. The program can no longer tell the two situations apart.

What it prints

We have 3 left.No count available.No count available.

The same function, asking what it means

Three explicit questions replace one vague one. The code is two lines longer and now distinguishes all three situations correctly.

1function reportStock(count) {2  if (typeof count !== "number") {3    console.log("No count available.");4  } else if (count === 0) {5    console.log("Out of stock.");6  } else {7    console.log("We have " + count + " left.");8  }9}10 11reportStock(3);12reportStock(0);13reportStock(undefined);
  • line 2

    The 'was anything supplied' question, asked directly: is this a number at all? undefined is not, so it takes this branch.

  • line 4

    Now that we know it is a number, 0 gets its own answer instead of being lumped in with missing data.

  • line 6

    Everything left is a number that is not 0. Compare the three output lines below with the previous example's.

What it prints

We have 3 left.Out of stock.No count available.

Check yourself

Not scored, not stored. Getting one wrong is the useful part.

Exactly one of these four values is truthy. Which one?

items is an empty array. Predict both lines before you look: one asks about the array, the other asks about its length.

const items = [];if (items) {  console.log("the array itself is truthy");}if (items.length) {  console.log("it has items");} else {  console.log("it is empty");}

A function receives a temperature reading that may be missing, and 0 degrees is a perfectly valid reading. Which test correctly asks 'was a reading supplied?'

Write it yourself

Exercise · core · 9 tests

Is this value blank?

Write isBlank(value) that returns true when a value counts as blank and false otherwise. Blank means exactly three things: the value is null, or it is undefined, or it is text that is empty or contains nothing but spaces. Everything else is not blank - in particular the number 0 is not blank, and false is not blank. You will need value.trim(), which gives you the same text with the spaces removed from both ends, so " ".trim() has length 0. Do NOT reach for bare truthiness here; the whole point is that it would get 0 and false wrong.

What your code must do

isBlank returns true for null, for undefined, and for any string whose trimmed length is 0. It returns false for every other value, including 0, false, and any string with at least one non-space character. It always returns a boolean and never prints anything.

Define isBlank at the top level of your code — the tests call it by name.

Runs on your device in a sandbox with no network and no access to this page.

Worth remembering

  • Name every falsy value in JavaScript.

    false, 0, -0, 0n, the empty string, null, undefined, NaN. Everything else is truthy - including "0", "false", [] and {}.

  • Is an empty array truthy or falsy, and why?

    Truthy. No object appears on the falsy list, so the conversion never looks inside. Ask items.length > 0 to find out whether it has contents.

  • Why is 'if (count)' risky when count is a number?

    0 is falsy, so a genuine count of zero is treated as missing. Ask the question you mean: count !== undefined, or count > 0.

Check this lesson against the source

We wrote the explanation; we did not invent the facts. This is the page that backs them.

MDN — Falsy (Glossary)

Check there: A falsy value is one that is considered false when encountered in a boolean context, and the page lists exactly false, 0, -0, 0n, "", null, undefined and NaN (plus document.all).

MDN — Truthy (Glossary)

Check there: All values are truthy unless they are defined as falsy.

MDN — Boolean() constructor

Check there: Boolean(value) performs the same conversion used by conditional statements.

Prefer to read the source in a structured breakdown? Turn this doc into a breakdown

0 of 1 exercise in this lesson solved on this device

Consent version 2026-07-31.1

Cookie preferences