Topic 2.3
Conditions: if, else and the Ternary
In one line
if runs a block of code only when a condition is truthy, else if and else add other paths, and the ternary condition ? a : b is the expression version that picks one of two values.
Think of it like this
Getting dressed in the morning. If it's raining, take an umbrella. Else if it's sunny, take sunglasses. Else, take nothing extra. You check the conditions in order and do only the first one that fits. A program decides the same way, thousands of times a second.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Control flow
- The order in which the statements of a program run.
- Condition
- An expression checked for true or false, like
age >= 18. - Block
- A group of statements inside
{ }that runs together. - Branch
- One of the possible paths through an
if/elsechain. - Statement vs expression
- A statement does something (
if,let); an expression produces a value (2 + 2,a ? b : c). - Ternary operator
condition ? a : b: givesaif the condition is truthy, otherwiseb.- Guard clause
- An early check that leaves a function straight away when something is wrong, keeping the rest of the code flat.
Step by step
01One condition, one block
The simplest form: if the condition is truthy, run the block. Otherwise skip it.
const temperature = 32;
if (temperature > 30) {
console.log("It's hot. Drink water.");
}
console.log("This line always runs.");02Add the other path with else
else catches everything the if didn't. Exactly one of the two blocks runs, never both, never neither.
const age = 15;
if (age >= 18) {
console.log("You can vote.");
} else {
console.log("Not yet.");
}03Chain several conditions
else if checks the next condition only if all earlier ones were false. The first match wins, so order from most specific to least.
04Pick a value with the ternary
When both branches only produce a value, the ternary is shorter and can sit inside other expressions.
const items = 1;
console.log(`You have ${items} ${items === 1 ? "item" : "items"}`);05Flatten with guard clauses
Handle the problem cases first and stop. What's left is the happy path, with no extra indentation. (You'll use return inside functions in Phase 3.)
function checkout(cart) {
if (!cart) return "No cart";
if (cart.items.length === 0) return "Cart is empty";
return "Paying for " + cart.items.length + " items";
}Try it yourself
- 1
Test the edges
In the first example, predict the grade for
75,74.9and-5, then type each one and press the button. Edges (exactly 75, exactly 50) are where bugs hide. - 2
Reorder the branches
Move the
score >= 50branch to the top of the chain. Predict: what does95get now? (C, because the first true branch wins.) Put it back. - 3
Open the shop
In the second example, change
hourto10. Predict the text, the colour and the console line before running.
Code & diagrams
Type a score and press the button. The first matching branch wins, so `90` is an A and not also a B or C.
Preview
Console
Nothing logged yet.Expected console output
A B C F
A BThe ternary sits inside a template literal and on the right of `=`, places where an `if` statement can't go. The nested one at the end works, but an `if` chain would be easier to read.
Preview
Console
Nothing logged yet.Expected console output
closed medium`if (stock)` can't tell "zero" from "missing". Say what you mean with a comparison.
Console
(nothing was printed)Expected console output
A: treated as missing
B: stock is known: 0
C: please enter a name
D: sold outBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Use = instead of === in a condition
In the third example, change const stock = 0; to let stock = 0;, then change if (stock !== undefined) to if (stock = 5).
Break #2
Leave out the braces, then add a line
Write if (false) console.log("one"); console.log("two"); on two indented lines as if both belong to the if.
Myth vs fact
Myth
Several else if branches can run if several conditions are true.
Fact
Only the first truthy branch runs. Use separate if statements (no else) if you want every matching block to run.
Myth
The ternary is just a shorter if.
Fact
It's an expression that produces a value; if is a statement. You can't put return or a for loop inside a ternary branch, and you can't assign an if to a variable.
Myth
if (x) checks whether x exists.
Fact
It checks whether x is truthy. 0, "" and NaN exist but are falsy. Use x !== undefined, x != null (both null and undefined) or a comparison when those values matter.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Modern CPUs guess which way a branch will go (branch prediction). Predictable branches (almost always true or almost always false) are very cheap; random ones in hot loops cost more. JIT engines also optimise for the paths they have seen, so a branch that suddenly takes a new path may trigger deoptimisation. This only matters in very hot code.
- ▸
x != null(loose) is the one widely accepted use of==: it's true for exactlynullandundefinedand false for everything else, so it's a compact "is present" check. Many style guides allow it as an exception to "always ===". - ▸
A function declared inside an
ifblock has different behaviour in strict mode (block-scoped) and sloppy mode (web-compat hoisting rules from the spec's Annex B). Avoid declaring functions inside blocks; assign a function expression to aconstinstead. - ▸
When an
if/else ifchain only maps a value to another value, a lookup object orMapis often clearer and faster to extend (Topic 2.4 shows this).
Remember this
- 1
Control flow is the order in which a program's statements run. Normally it's top to bottom. A conditional statement changes that: it runs some code only when a condition is met.
if (condition) { ... }evaluates the condition, converts the result to a boolean with the truthy/falsy rules (Topic 1.6), and runs the block (the code between{and}) only if it is truthy. If not, it skips the block and carries on after it. - 2
else { ... }runs when theifcondition was falsy.else if (other) { ... }adds another condition to check. A chain ofif/else if/elseis checked top to bottom, and only the first truthy branch runs; the rest are skipped, even if they would also be true. So order matters: put the most specific conditions first (checkscore >= 90beforescore >= 50). - 3
Conditions are usually comparisons (
age >= 18), equality checks (status === "paid") and logical combinations (isAdmin || isOwner, Topic 2.2). Because the condition is converted to a boolean,if (name)means "ifnameis not empty,0,nullorundefined". That's handy, but be careful:if (count)is false whencountis0, which is often a real value. Writeif (count !== undefined)orif (count > 0)to say exactly what you mean. - 4
The ternary operator
condition ? valueIfTrue : valueIfFalseis the only JavaScript operator with three operands. It's an expression: it produces a value, so you can put it in a variable, a template literal or a function argument:const label = age >= 18 ? "adult" : "child";. Anifis a statement: it does something but has no value. Use the ternary to choose between two values, andifto choose between two actions. Nested ternaries (a ? b : c ? d : e) work but get hard to read fast. - 5
Guard clauses keep code flat. Instead of wrapping a whole function in
if (valid) { ...lots of code... }, check the bad cases first and leave early:if (!user) return;. This early return style (you'll write functions in Phase 3) avoids deep nesting, sometimes called the "pyramid of doom". - 6
Braces:
if (x) doThing();without{}is allowed, but only the next single statement belongs to theif. Adding a second indented line later doesn't make it part of theif, which is a classic bug (Apple's 2014 "goto fail" security bug in C was exactly this). Most style guides require braces always. Also note that variables declared withletorconstinside a block exist only inside that block (block scope, Topic 3.4).
Explain it without notes
How does an if / else if / else chain decide which block to run?
What is the difference between if and the ternary operator?
What is a guard clause, and why do people use it?
Why can if (count) be a bug?
Practice
Write code that prints fizz if n is divisible by 3, buzz if by 5, fizzbuzz if by both, and the number otherwise. Test with n = 15, 9, 10 and 7.
Use a ternary to print 1 item or N items for const n = 1 and const n = 4.
Rewrite this with a guard clause: if (age !== undefined) { if (age >= 18) { console.log("adult"); } else { console.log("minor"); } }.
Trade-offs
- ↔
Long
if/else ifchains are easy to write but hard to extend; a lookup table scales better when you're only mapping values. - ↔
Nested ternaries are compact but slow to read; past one level, an
ifchain or a small function is kinder to the next reader.
Done when you can
I can write
if,else ifandelse, and predict which branch runs.I can order conditions so the most specific one is checked first.
I can use the ternary to choose a value inside an expression.
I can avoid the
if (count)trap when0or""are valid.I always use braces and
===in conditions.