if, else & conditions
Run code only when a condition is true, choose exactly one branch, and simplify decisions with blocks, truthy checks, and early returns.
- 01Choose one pathTrace an if / else-if / else chain and predict which branch runs.
- 02Use blocks safelyKnow what braces control, why missing braces are risky, and how block scope works.
- 03Write clearer checksUse truthy conditions when they help and guard clauses when they flatten nested code.
Make decisions with code
A program does not always run every line. Sometimes it should greet a signed-in user and ask a guest to sign in. Sometimes it should show a warning only when a form is incomplete. JavaScript makes those choices with conditionals: statements that run code only when a condition is truthy.
An if statement asks a yes/no question. If the answer is yes, JavaScript runs the block. If the answer is no, JavaScript skips that block and may try an else if or else.
Imagine walking along a path and reaching a sign. If the sign says the bridge is closed, you take the detour. Otherwise you keep going. The sign does not move your feet by itself; it only decides which path you follow next. An if statement works the same way.
- In real life: A signpost saying “Bridge closed”
- In JavaScript: The condition:
bridgeClosed - In real life: Taking the detour path
- In JavaScript: The block inside
if (...) { ... } - In real life: Continuing straight when the sign is false
- In JavaScript: Skipping the block
Where the analogy stops: Road signs are usually obvious to humans. JavaScript only knows the exact truthy or falsy value produced by your condition.
You already met booleans, comparisons, logical operators, nullish and optional chaining, the ternary operator, and block statements. This lesson connects those tools: comparisons and logical operators often create the condition, while blocks hold the code that should run. If truthy and falsy values feel fuzzy, revisit Booleans & truthiness.
if, else if, else: first true branch wins
STEP THROUGHThe most common shape is a chain. JavaScript checks the first condition. If it is false, it checks the next else if. If every condition is false, the final else is the fallback. In one trip through the chain, only one branch runs.
Step through the temperature example. Change line 1, predict the first true condition, then watch later branches get skipped.
Predict which branch will run. Then step through each condition until the first true one wins.
script
let clothing; if (temperature < 0) { clothing = "heavy coat";} else if (temperature < 15) { clothing = "jacket";} else if (temperature < 30) { clothing = "t-shirt";} else { clothing = "stay cool";}console.log(clothing);Picture a letter sliding down a sorting machine. It drops into the first slot that matches its label. A letter for “local mail” never reaches the “everything else” bin after it has already fallen into the local slot.
- In real life: First slot: international mail
- In JavaScript: First
ifcondition - In real life: Second slot: local mail
- In JavaScript: Next
else ifcondition - In real life: The first matching slot catches the letter
- In JavaScript: The first true branch runs
- In real life: Later slots never see that letter
- In JavaScript: Later branches are skipped
Where the analogy stops: A physical sorter may keep scanning for quality checks. An if / else-if / else chain stops as soon as one branch matches.
Try the same idea as a sorting game. Which branch would each input choose?
- temperature is -4
- temperature is 0
- temperature is 14
- temperature is 15
- temperature is 29
- temperature is 30
- temperature is 38
- temperature is -12
Sort each temperature into the message chosen by the if / else-if / else chain.
Order matters: put specific checks first
INTERACTIVEBecause an else-if chain stops at the first true condition, the order of checks is part of the logic. A broad condition can accidentally swallow a more specific one.
In this grade calculator, score >= 50 is true for a score of 91. If that check comes first, the score >= 90 branch never gets a chance.
function grade(score) { if (score >= 50) return "pass"; if (score >= 90) return "excellent"; return "try again";}45507291Wrong order: score 91 returns pass because score >= 50 is true first. The later excellent check is never reached.
Start with the narrowest or most exceptional cases, then move toward broader fallbacks. This is the same idea you used in the Comparisons and Logical operators lessons: write the condition that says exactly what you mean.
Blocks: braces fence in the controlled statements
SAFETYA block is code between braces: { and }. In an if statement, the block is the fenced area on that path. Every statement inside the braces depends on the condition.
const isAdmin = true;if (isAdmin) { console.log("show admin link"); console.log("delete account enabled");}JavaScript allows a one-line if without braces, but it controls only the next statement. Indentation does not matter to the language, so this classic bug is easy to miss in review:
const isAdmin = false;if (isAdmin) console.log("show admin link"); console.log("delete account enabled");if (isAdmin); is a complete if statement with an empty body. The block after it is just a normal block, so it always runs. The Statements, comments & semicolons lesson warned about this tiny character because it changes control flow completely.
Blocks also create scope for let and const. A variable declared inside an if block belongs to that block. That keeps names tidy; later Scope lessons go deeper.
Truthy conditions: conditions do not have to be booleans
INTERACTIVEThe condition inside if (...) can be any value. JavaScript converts it to a yes/no decision. Values that act like yes are truthy; values that act like no are falsy. The main falsy values are false, 0, "", null, undefined, and NaN. Almost everything else is truthy.
const value = "0"; if (value) { console.log("branch runs");} else { console.log("branch skipped");}"0"value !== """0" is truthy, so the program prints "branch runs". A clearer production check might be value !== "".
| Code | What it asks | When it is clearer |
|---|---|---|
if (name) | Is name truthy? Empty string, null, and undefined all skip. | Great for required text when empty means missing. |
if (items) | Is the array object truthy? Even [] runs. | Usually too vague for arrays. |
if (items.length > 0) | Does the array contain at least one item? | Clear when emptiness matters. |
if (value !== undefined) | Was a value provided at all? | Clear when 0 or "" are valid values. |
If 0 is a valid count, if (count) may hide it by accident. Prefer if (count !== undefined) or if (count >= 0), depending on the real rule.
Early returns: guard the door, then keep the main path flat
STEP THROUGHFunctions get a full module next, but you can read this pattern now: return leaves a function immediately. An early return uses that to handle a failure case near the top.
Instead of letting everyone wander deep into a club and then trying to sort them out near the stage, a bouncer handles obvious problems at the entrance. Guard clauses do the same for functions.
- In real life: No ticket? Stop at the door.
- In JavaScript:
if (!user) return "Sign in first"; - In real life: Wrong wristband? Stop at the door.
- In JavaScript:
if (user.blocked) return "Account blocked"; - In real life: Everyone left inside is allowed
- In JavaScript: The final success return
Where the analogy stops: A real bouncer can discuss edge cases. A guard clause returns exactly the value you wrote and stops the function.
Switch between nested code and early returns. Both produce the same result, but the path feels different.
script
function checkout(user) { if (!user) return "Sign in first"; if (user.blocked) return "Account blocked"; if (user.cartItems === 0) return "Cart is empty"; if (!user.paymentReady) return "Add payment method"; return "Ready to checkout";}const result = checkout(user);console.log(result);The nested and early-return versions are logically equivalent for the inputs in the experiment. The early-return version is often easier to scan because each invalid case is handled and removed from the story. The success path stays at the left edge.
Where you'll use this
Conditionals appear anywhere code reacts to data:
- Show a loading, empty, error, or success message.
- Validate a form before submitting it.
- Choose a price, shipping option, or permission message.
- Return early from a function when required input is missing.
function statusMessage(user, cart) { if (!user) return "Please sign in."; if (cart.length === 0) return "Your cart is empty."; if (!user.paymentReady) return "Add a payment method."; return "Ready to checkout.";}| Use | Best fit | Why |
|---|---|---|
| Choose one small value | Ternary | const label = open ? "Open" : "Closed" is compact and readable. |
| Run several statements | if/else | Blocks can contain multiple lines, logs, returns, and assignments. |
| Handle many ordered cases | if / else if / else | Order and first-match behavior are visible. |
| Stop invalid function input | Early returns | Guard clauses avoid deep nesting. |
Common misconceptions
“Every true condition in an else-if chain runs.”
No. The first true branch runs, then the chain is finished.
“Indentation controls the if body.”
Indentation helps humans. Braces and statement boundaries control JavaScript.
“Truthy means equal to true.”
"0" and [] are truthy, but neither is the boolean true.
“else is required.”
An if can stand alone. Use else only when there is a real fallback path.
“Early returns are only for errors.”
They are for any decided case: missing user, empty cart, permission denied, or already complete.
Practice: choose the right path
5 EXERCISESPredict the exact word printed by this program.
const loggedIn = true;
const hasCart = false;
if (loggedIn && hasCart) {
console.log("checkout");
} else if (loggedIn) {
console.log("browse");
} else {
console.log("sign in");
}loggedIn && hasCart is false because hasCart is false. The next condition, loggedIn, is true, so the program prints browse.
The function should print excellent for 95, but the buggy version prints pass. Reorder the conditions.
function grade(score) {
if (score >= 50) return "pass";
if (score >= 90) return "excellent";
return "try again";
}
console.log(grade(95));function grade(score) {
if (score >= 90) return "excellent";
if (score >= 50) return "pass";
return "try again";
}
console.log(grade(95));The excellent check must come before the pass check. After the fix, grade(95) prints excellent.
Write the checkout logic using guard clauses: no user, blocked user, empty cart, missing payment, then success.
function canCheckout(user) {
if (!user) return "Sign in first";
if (user.blocked) return "Account blocked";
if (user.cartItems === 0) return "Cart is empty";
if (!user.paymentReady) return "Add payment method";
return "Ready to checkout";
}
console.log(canCheckout(null));
console.log(canCheckout({ blocked: false, cartItems: 2, paymentReady: true }));function canCheckout(user) {
if (!user) return "Sign in first";
if (user.blocked) return "Account blocked";
if (user.cartItems === 0) return "Cart is empty";
if (!user.paymentReady) return "Add payment method";
return "Ready to checkout";
}
console.log(canCheckout(null));
console.log(canCheckout({ blocked: false, cartItems: 2, paymentReady: true }));Each guard clause handles one stop case. If no guard returns, the shopper is ready, so the final return is the success message.
Which line still prints when isAdmin is false? Then add braces so neither admin-only line runs.
const isAdmin = false;
if (isAdmin)
console.log("show admin link");
console.log("delete account enabled");const isAdmin = false;
if (isAdmin) {
console.log("show admin link");
console.log("delete account enabled");
}Now both log statements are inside the block, so neither runs when isAdmin is false.
Write ticketPrice(age): under 5 is free, under 18 is 8, 65+ is 6, and everyone else is 12.
function ticketPrice(age) {
if (age < 5) return 0;
if (age < 18) return 8;
if (age >= 65) return 6;
return 12;
}
console.log(ticketPrice(3));
console.log(ticketPrice(16));
console.log(ticketPrice(40));
console.log(ticketPrice(70));function ticketPrice(age) {
if (age < 5) return 0;
if (age < 18) return 8;
if (age >= 65) return 6;
return 12;
}
console.log(ticketPrice(3));
console.log(ticketPrice(16));
console.log(ticketPrice(40));
console.log(ticketPrice(70));The function returns 0 for under 5, 8 for under 18, 6 for 65 and older, and 12 for everyone else. For age 70 it prints 6.
Quiz: check your understanding
7 QUESTIONSTrace each snippet carefully. Your first-try score counts, but every answer teaches.
Question 1 of 7Temperature branch: what does this print?
Read the code, then predictconst temp = 20; if (temp < 0) { console.log("coat"); } else if (temp < 30) { console.log("t-shirt"); } else { console.log("cool"); }Choose an answer to see the explanation.
Question 2 of 7In an else-if chain, what happens after the first true condition?
Choose an answer to see the explanation.
Question 3 of 7Truthy string: what does this print?
Read the code, then predictif ("0") { console.log("runs"); } else { console.log("skips"); }Choose an answer to see the explanation.
Question 4 of 7Why are braces useful around an if body?
Choose an answer to see the explanation.
Question 5 of 7Stray semicolon: what does this print?
Read the code, then predictconst isAdmin = false; if (isAdmin); { console.log("danger"); }Choose an answer to see the explanation.
Question 6 of 7Which version is usually clearer for validation failures at the top of a function?
Choose an answer to see the explanation.
Question 7 of 7Explicit length check: what does this print?
Read the code, then predictfunction label(items) { if (items.length > 0) return "has items"; return "empty"; } console.log(label([]));Choose an answer to see the explanation.
Key takeaways
ifruns a block only when its condition is truthy.else ifchains use first-match wins; later branches are skipped.- Braces create the block controlled by the condition and scope
let/constvariables. - Truthy checks are useful, but explicit checks are clearer for arrays, zero, and missing values.
- Early returns handle stop cases first and keep function logic flat.
Remember the one-liner.
Conditionals let JavaScript choose which code path to run.
Up next: The switch statement.