Boolean Logic in Javascript: Truthy - Falsy, and Equality Explained for Beginners

Sangy KSangy K
13 min read

Coding isn't just about telling computers what to do; it's about telling them when to do it. — It's about telling them how to make choices. 🧠

Should this run or not? Is this true or false? 🤔

Javascript gives us tools like Boolean logic, conditions, and equality checks to help our programs "decide" what to do.

Having a better understanding of these concepts helps us spend more time building cool stuff and less time chasing mysterious bugs.

In this deep dive, we'll get comfy with:

  • Boolean values – the language of true and false

  • Conditional logic – how our code makes decisions

  • Truthy and falsy – Javascript's "hidden" rules for what counts as true

  • == vs === – the infamous equality operators and their quirks

By the end, we'll think like Javascript does when it comes to decision-making.

Let's get into it. 🚀

Boolean Logic: The Language of Decisions

Boolean logic underpins almost everything in programming. A Boolean is the simplest type of value — it can only be:

  • true

  • false

Think of it like a light switch: it's either on (true) or off (false).

Why Booleans Matter

Booleans answer questions in our code:

  • Is the user logged in? → true or false

  • Does this number exceed 100? → true or false

  • Did we finish loading the data? → true or false

They're the yes/no checkpoints that drive all our conditions.

let isLoggedIn = true;

if (isLoggedIn) {
  console.log("Welcome back!");
} else {
  console.log("Please log in.");
}

Here, isLoggedIn determines which branch of code to run. Change it to false, and we get the other path.

Logical Operators: Combining Truths

In programming, we often make decisions that depend on more than one condition.

Logical operators, also known as Boolean operators, enable us to combine and modify conditions, allowing our programs to make more informed decisions. They're essential when we want to check more than one thing at the same time.

  • AND (&&) → Returns true only if both sides are true.

  • OR (||) → Returns true if at least one side is true.

  • NOT (!) → Flips a Boolean: truefalse, falsetrue.

Example:

let hasTicket = true;
let seatAvailable = false;

console.log(hasTicket && seatAvailable); // false — both must be true
console.log(hasTicket || seatAvailable); // true — at least one is true
console.log(!hasTicket); // false — flips true → false

Short-Circuiting: Why Javascript Doesn't Always Check Everything

Logical operators in Javascript short-circuit, meaning they stop evaluating as soon as the result is clear:

  • For &&, if the first value is false, Javascript won't bother checking the second — the whole thing must be false anyway.

  • For ||, if the first value is true, Javascript immediately returns it and skips the second.

This isn't just for speed; we can use it to write cleaner code:

let user = null;
let defaultName = "Guest";

console.log(user || defaultName); // "Guest" — user is null, so fallback applies

And here's a gotcha: logical operators (&& and ||) aren't just used to combine conditions and return true or false. In Javascript, they often return one of the original values instead of a plain Boolean — there's more going on under the hood!

Conditional Statements: Teaching Code to Choose

Once we have Boolean values, we use conditions to control what happens next.

if Statements – The Basic Gatekeeper

The simplest decision-maker is if. It says: "Run this code only if this condition is true."

let age = 20;

if (age >= 18) {
  console.log("You’re an adult!");
}

Perfect for simple checks.

if…else and else if – Handling Multiple Paths

Sometimes, we need to take different actions based on specific conditions. That's where else and else if come in:

let score = 75;

if (score >= 90) {
  console.log("Grade A");
} else if (score >= 75) {
  console.log("Grade B");
} else {
  console.log("Keep practicing!");
}

Javascript checks each condition in order and stops at the first match.

Tip: Put the most likely conditions first. Too many else if chains? A switch might be cleaner.

Real-World Case: Feature Toggles

Imagine we're building an app and want to enable a new feature only for beta users:

let isBetaUser = true;
let featureEnabled = false;

if (isBetaUser && featureEnabled) {
  console.log("Enjoy the new feature!");
} else {
  console.log("Coming soon!");
}

We're using both Booleans and a condition to control who sees what.

Conditional Gotchas

Truthy and Falsy: Javascript's Hidden Rules

In Javascript, not everything that behaves like true or false is literally the Boolean values true or false.

Any value can act as true (we call it truthy) or false (falsy) when Javascript expects a Boolean — for example, inside an if statement, a loop condition, or with logical operators.

This concept can be a bit tricky to grasp at first, but understanding it is crucial for writing reliable conditional code in Javascript.

Think of it like a simple yes/no test: Javascript asks, "Does this value count as something?" If yes → truthy; if no → falsy.

Falsy Values: The Exclusive Seven

Javascript only treats seven specific values as falsy. Everything else counts as truthy. Here they are:

  • false — the Boolean value for "no."

  • 0 — the number zero. Even though other numbers (positive or negative) are truthy, 0 is falsy.

  • "" — an empty string, meaning no characters inside quotes.

  • null — a deliberate "no value" placeholder.

  • undefined — a variable exists but hasn't been given a value yet.

  • NaN — "Not-a-Number," which you get from invalid math like 0 / 0 or parseInt("abc").

  • 0n — BigInt zero, the BigInt version of 0, also falsy.

Examples:

if (0) console.log("Will this run?"); // No, 0 is falsy.
if ("") console.log("Empty string?"); // Nope, falsy.
if (undefined) console.log("Undefined?"); // Also falsy.

In all three cases, Javascript skips the console.log() because the values fail the "Does this value count as something?" test.

Everything Else is Truthy

Anything not on that list is truthy — even values that feel "empty" or "false-like" to us:

if ("0") console.log("String containing zero is truthy!");
if ([]) console.log("Even an empty array counts as truthy!");
if ({}) console.log("Empty object? Truthy as well!");
  • "0" is a non-empty string, so it's truthy, even if it represents zero.

  • [] and {} are objects. In Javascript, all objects are truthy, even when they're empty.

This catches beginners off guard: an empty array (`[]`) or an empty object (`{}`) in an if check doesn't behave like false.

How if (value) Works Behind the Scenes

When we write:

if (expression) {
  console.log("This runs if value is truthy.");
}

Javascript automatically evaluates the expression and converts the returned value into a Boolean using a process called type coercion:

  • If the returned value is one of the seven falsy values, it becomes false and the block is skipped.

  • Otherwise, it becomes true, and the block runs.

Example:

let name = "Luna";

if (name) {
  console.log("Hello, " + name + "!");
}
  • "Luna" is a non-empty string, so Javascript converts it to true.

  • The message prints: Hello, Luna!

Real-Life Use Case: Input Validation

Truthy/falsy checks excel in everyday tasks, such as form validation.

Suppose we want to verify that a user actually entered a name:

let username = "";

if (!username) {
  console.log("Please enter your name.");
}
  • username is "", an empty string — falsy.

  • !username flips falsy to true, so the message prints: "Please enter your name."

Why this is useful: Instead of writing if (username === ""), we rely on Javascript's built-in truthiness to handle all "empty" cases.

Gotchas with Truthy/Falsy

Empty arrays and objects are truthy

if ([]) console.log("Runs, because [] is truthy!");
if ({}) console.log("Runs, because {} is truthy!");

Even though they contain "nothing," arrays and objects are always truthy because they're still real, allocated values.

Loose equality and accidental coercion

console.log("0" == false); // true 😬
  • Here, Javascript converts both sides before comparing: "0"0false.

  • This is why we almost always prefer ===, which avoids these conversions.

Why Understanding Truthy/Falsy Matters

Beginners often get tripped up when Javascript silently converts values. Knowing these rules helps us:

  • Write reliable conditions (if, while, etc.)

  • Avoid bugs caused by unexpected type coercion

  • Quickly check if a variable has "something meaningful" in it

Quick tip: Be explicit when needed. Instead of relying on truthiness, check precisely what you want:

if (username.length === 0) {
  console.log("Username is empty.");
}

This avoids surprises from values like [], {}, or "0".

Non-Boolean Returns — Why Logical Operators Don't Always Give true or false

We usually think of logical operators (&&, ||) as tools that return a true or false answer, but in Javascript, that's not always the case. Instead of strictly returning true or false, they often give us the actual value of one of the operands.

Here's what's happening:

  • && (AND) returns the first falsy value it finds. If none are falsy, it returns the last value.

  • || (OR) returns the first truthy value it finds. If none are truthy, it returns the last value.

Alright, let's melt that brain freeze with an example ❄️➡️🔥

console.log("Luna" && "Marco"); // "Marco"
console.log("Luna" || "Marco"); // "Luna"

Why? Both "Luna" and "Marco" are truthy (not empty, not false, not zero). && goes all the way through and returns the last value, "Marco". Similarly || returns the first truthy value, "Luna"

Another example:

console.log("" || "Default"); // "Default"

The first value "" is falsy (empty string), so || skips it and returns the first truthy value, "Default".

This behaviour is why we often see logical operators used for default values:

let username = userInput || "Anonymous";
console.log(username); // If userInput is empty, use "Anonymous"

Or for safe function calls:

user && sendEmail(user);  // sendEmail runs only if user exists (is truthy)

Why does this matter?

It's convenient, but it can also lead to unexpected surprises. For example:

console.log(0 || 42); // 42 — but 0 might be a valid value!

Here, 0 is falsy, so || ignores it and gives us 42, even though we might have wanted to keep 0.

Takeaway: Logical operators return one of their original values, not always true or false. Knowing this helps us write cleaner code and avoid unexpected "magic" values.

Equality in Javascript: == vs ===

Equality checks are one of Javascript's most famous "gotchas" — the places where beginners get tripped up most often. Two operators look almost the same — == and === — but they behave very differently. Let's break it down step by step.

The Loose Equality Operator: ==

The loose equality operator == checks if two values are "equal" — but it allows type coercion.

That means before comparing, Javascript tries to convert both values to the same type.

console.log("5" == 5); // true 😬
  • "5" is a string, and 5 is a number.

  • == converts the string "5" into the number 5, then compares 5 == 5, which is true.

console.log(false == 0); // true
  • false becomes 0 when coerced to a number.

  • Now it's 0 == 0, which is true.

console.log("" == false); // true
  • "" (empty string) becomes 0, and false also becomes 0.

  • So, 0 == 0 → true.

The problem?

== tries too hard to find equality, often resulting in surprising matches.

It's like comparing apples to boxes of apples — Javascript opens the box and says, "Well, if I squint, they're the same!"

The Strict Equality Operator: ===

The strict equality operator === is much more stringent. It does not allow type coercion.

For two values to be strictly equal:

  1. They must have the same value.

  2. They must have the same type.

The strict equality operator === first checks if both values have the same type. If the types don't match, it immediately returns false. If the types do match, it then checks whether the values themselves are the same. Only when both type and value match does it return true.

Examples:

console.log("5" === 5); // false
  • "5" is a string, 5 is a number.

  • Types are different, so === immediately returns false.

console.log(5 === 5); // true
  • Both are numbers, and both have the value 5.

  • So === returns true.

When Should We Use Which?

  • Use === by default. It's predictable, avoids type coercion, and saves us from weird bugs.

  • Use == only when we intentionally want type conversion — which is very rare in modern Javascript.

Think of it like this:

  • == says, "If I do a little mental gymnastics, these could be the same."

  • === says, "No squinting — they must match exactly, both in type and value."

Edge Cases: NaN and Object.is()

Here's a fun (and confusing!) fact:

console.log(NaN === NaN); // false

  • NaN (Not-a-Number) is the only value in Javascript that is not equal to itself.

  • Why? Because by definition, "not a number" can't equal any number — not even itself.

How do we check for NaN?

console.log(Number.isNaN(NaN)); // true

console.log(Object.is(NaN, NaN)); // true

  • Number.isNaN() and Object.is() correctly tell us if a value is NaN.

Why Does This Matter?

Using == can lead to bugs that are difficult to spot, as type coercion occurs behind the scenes.

console.log(0 == ""); // true 😬

console.log(false == "0"); // true 🤯

We might expect these to be false, but == converts both sides to numbers, then compares.

By sticking to ===, we make our comparisons crystal clear — no hidden conversions, no surprises.

Takeaway

  • Always prefer === and !== — they're safer and more predictable.

  • Use == only when you fully understand and want its coercion behaviour.

  • Remember: Type coercion is one of Javascript's most common beginner traps.

Putting It All Together

Let's see a practical example where we combine everything we've learned — truthy/falsy checks, number validation, type conversion, and conditional logic:

let userInput = prompt("Enter your age:");

if (userInput && !isNaN(userInput)) {
  let age = Number(userInput); // convert the string to a number

  if (age >= 18) {
    console.log("Access granted!");
  } else {
    console.log("Sorry, you must be 18 or older.");
  }
} else {
  console.log("Please enter a valid number.");
}

What's happening here?

  • We check if userInput is truthy: prompt() always returns a string. If the user leaves it blank, it's an empty string "", which is falsy.

  • We ensure the input is a number: isNaN(userInput) tries to convert the input to a number and checks if it's "Not a Number." We use !isNaN(userInput) to confirm that it's a numeric value.

  • We convert the input to a number: Number(userInput) converts the input string into a numerical value for comparison.

  • We make a decision:

    • If age >= 18, we grant access.

    • Otherwise, we inform the user that they must be at least 18 years old.

  • Invalid input? We ask them to enter a valid number.

This example shows how truthy/falsy checks, proper type handling, and conditionals work together to make our programs reliable and user-friendly.

Key Takeaways

  • Booleans are the foundation of all decision-making in Javascript.

  • Conditions let our programs react dynamically — doing the right thing at the right time.

  • Truthy and falsy values decide whether a block runs or not.

  • Use === for equality checks to avoid surprising type coercion.

  • Always validate user input — never trust raw data.

What's Next?

Now that we've got a handle on control flow, loops, and operators, it's time to dive into one of the most crucial and exciting parts of Javascript — functions. They're the building blocks of all reusable and modular code.

Stay tuned — we're just getting started! 🚀

0
Subscribe to my newsletter

Read articles from Sangy K directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sangy K
Sangy K

An Introvert Coder | Trying to be a Full-stack Developer | A Wannabe Content Creator