Booleans and Logic
True, false, and the operators that let a program reason about combinations of conditions.
A boolean is a value that is either true or false. There
are only two of them. They are the smallest, simplest, and possibly
the most important type in the language — because every decision a
program ever makes is, at the bottom, a boolean.
Where booleans come from
You rarely write the literals true and false directly.
Booleans usually come from comparisons and logical
expressions.
Comparison operators
| Operator | Meaning | Example | Result |
|---|---|---|---|
=== | strictly equal | 5 === 5 | true |
!== | strictly not equal | 5 !== 6 | true |
< | less than | 3 < 4 | true |
> | greater than | 3 > 4 | false |
<= | less than or equal | 3 <= 3 | true |
>= | greater than or equal | 5 >= 6 | false |
(The loose == and != exist too; we will keep avoiding them.)
A surprising one: strings can be compared with <, >, etc. They
compare lexicographically (dictionary order, but using the
Unicode code point of each character). This matters because
uppercase letters have lower Unicode values than lowercase ones,
so "Z" < "a" is true. When comparing user-facing text, use
locale-aware methods like "a".localeCompare("B").
The three logical operators
Once you have boolean values, you combine them with three logical operators:
| Operator | Name | Read as | Example | Result |
|---|---|---|---|---|
&& | AND | "both" | true && false | false |
|| | OR | "either" | true || false | true |
! | NOT | "not" | !true | false |
Truth tables
The classic way to learn the operators is a tiny table:
a && b
a | b | a && b |
|---|---|---|
false | false | false |
false | true | false |
true | false | false |
true | true | true |
a || b
| a | b | a || b |
| :---: | :---: | :---: |
| false | false | false |
| false | true | true |
| true | false | true |
| true | true | true |
!a
a | !a |
|---|---|
false | true |
true | false |
Short-circuit evaluation
This is one of the most useful properties of && and ||:
a && bonly evaluatesbifais truthy. Ifais falsy, the result isaandbis never touched.a || bonly evaluatesbifais falsy. Ifais truthy, the result isaandbis never touched.
This is called short-circuit evaluation. The right-hand side might never run.
Two practical patterns use short-circuiting all the time:
- Default values:
const greeting = name || "stranger";→ ifnameis empty/falsy, use"stranger". - Safe conditional action:
user && user.notify();→ only callnotify()ifuseris truthy.
In modern code, the special nullish coalescing operator ??
is often a better choice than || for defaults, because it only
triggers on null/undefined (not 0 or ""):
Pick ?? when you specifically mean "fall back if missing", and
|| when you mean "fall back if falsy (empty, zero, false, …)".
Truthy and falsy, revisited
Recall from Values and Types — every value can be used in a boolean context. The falsy values are:
false0(and-0,0n)""nullundefinedNaN
Everything else is truthy. That fact unlocks short, readable idioms:
The if (name) check covers all "missing or empty" cases at once.
This is concise and idiomatic — just remember it also rules out
0 and false, which sometimes matters.
De Morgan's laws (very useful!)
Two algebraic identities that come up constantly in real code:
!(a && b)is equivalent to!a || !b!(a || b)is equivalent to!a && !b
In plain English: "not both" is "not one, or not the other", and "neither" is "not one, and not the other".
These are not just pedantic. They let you simplify confusing negations into cleaner conditions.
The ternary expression: a ? b : c
This is not strictly a logic operator, but it lives in the same neighbourhood. The ternary operator lets you choose between two values based on a condition:
const result = condition ? valueIfTrue : valueIfFalse;Use it for small, single-line choices. For anything more
complicated, use a regular if/else — readability beats
cleverness.
A worked example: a tiny rule engine
Below is a small example that combines comparisons, logical
operators, truthy/falsy, and the ternary. It models a "can this
user post a comment?" rule. Read each canComment line carefully —
it expresses a fairly complex business rule in a single, readable
line.
That single boolean expression in canComment encodes a rule that
might take a paragraph of English to describe. This is why
booleans are the most powerful tiny thing in programming.
Challenge
A year is a leap year if it is divisible by 4, except that years divisible by 100 are not leap years, unless they are also divisible by 400.
Examples:
- 2024 →
true(divisible by 4) - 1900 →
false(divisible by 100 but not 400) - 2000 →
true(divisible by 400) - 2023 →
false
Write isLeapYear(year) that returns the correct boolean.
What does "short-circuit evaluation" mean for the && operator?
Both sides are always evaluated, but only the first matters
The right side is evaluated only if the left side is truthy; otherwise the left side is returned without ever touching the right
It produces a shorter machine-code instruction
It only works for boolean values, not truthy/falsy ones