Every value in JavaScript is either "truthy" or "falsy" when it's evaluated in a boolean context — like the condition of an if statement, a while loop, or either side of && and ||. Understanding this is essential, because JavaScript will happily let you put a string, a number, or an object directly inside an if condition without explicitly converting it to true or false first.

The 8 Falsy Values

JavaScript has exactly eight falsy values. Everything else in the entire language is truthy.

// The 8 falsy values:
false
0
-0
0n        // BigInt zero
""        // empty string
null
undefined
NaN

That means even things that feel "empty" — like an empty array [] or an empty object {} — are actually truthy, which surprises a lot of developers coming from other languages.

if ([]) {
  console.log("Empty array is truthy!");
}

if ({}) {
  console.log("Empty object is truthy!");
}

if ("0") {
  console.log('The string "0" is truthy — only the empty string is falsy!');
}

Output:

Empty array is truthy!
Empty object is truthy!
The string "0" is truthy — only the empty string is falsy!

Truthiness in Short-Circuit Operators

&& and || don't actually return true/false — they return one of their original operand values, based on truthiness. This is used constantly for default values and conditional rendering.

const username = "";
const displayName = username || "Guest"; // "" is falsy, so this falls back
console.log(displayName);

const isLoggedIn = true;
isLoggedIn && console.log("Showing dashboard..."); // only runs if truthy

Output:

Guest
Showing dashboard...

The Nullish Coalescing Operator (??) as a Safer Alternative

The || fallback pattern has a gotcha: it treats 0, "", and false as "missing" too, even when they're legitimate values you meant to keep. The ?? operator only falls back on null or undefined specifically:

const quantity = 0;

console.log(quantity || 10); // 10 — wrong! 0 was a real value
console.log(quantity ?? 10); // 0 — correct, only null/undefined trigger the fallback

Output:

10
0

Use ?? whenever a falsy-but-valid value like 0 or "" should be preserved, and reserve || for cases where you genuinely want to treat every falsy value as "use the default instead."