Conditions
Make decisions in your code with if/else, else if, and switch statements.
1. Introduction
Real programs need to make decisions. Should the user be shown a login page or a dashboard? Is the form input valid? Did the user score above 50? These decisions are handled with conditional statements.
Conditional statements run different blocks of code depending on whether a condition is true or false. Without them, your code would always do the exact same thing — no branching, no logic, no interactivity.
This lesson covers:
ifstatementif / elseif / else if / elseswitchstatement- Guard clauses (early returns)
2. Theory
2.1 The if statement
Run code only if a condition is true:
if (condition) {
// runs only if condition is truthy
}
// Example
const temperature = 30;
if (temperature > 25) {
console.log('It is hot outside!');
}
// → 'It is hot outside!' (because 30 > 25 is true)
The condition inside ( ) is evaluated as a boolean. Any truthy value runs the block; any falsy value skips it.
2.2 if / else
Provide an alternative for when the condition is false:
const hour = 14; // 2 PM
if (hour < 12) {
console.log('Good morning!');
} else {
console.log('Good afternoon!');
}
// → 'Good afternoon!'
2.3 if / else if / else
Check multiple conditions in order — the first matching branch runs and the rest are skipped:
const score = 75;
if (score >= 90) {
console.log('Grade: A');
} else if (score >= 80) {
console.log('Grade: B');
} else if (score >= 70) {
console.log('Grade: C');
} else if (score >= 60) {
console.log('Grade: D');
} else {
console.log('Grade: F');
}
// → 'Grade: C'
Always place more specific conditions first (higher threshold first when checking >=).
2.4 Nested if statements
const isLoggedIn = true;
const isAdmin = false;
if (isLoggedIn) {
if (isAdmin) {
console.log('Welcome, Admin!');
} else {
console.log('Welcome, User!');
}
} else {
console.log('Please log in.');
}
// → 'Welcome, User!'
Avoid deep nesting — it becomes hard to read. Prefer early returns (guard clauses) instead.
2.5 The switch statement
switch compares one value against multiple cases. Use it when you have many discrete options for a single variable.
const day = 'Monday';
switch (day) {
case 'Monday':
case 'Tuesday':
case 'Wednesday':
case 'Thursday':
case 'Friday':
console.log('Weekday — work day');
break;
case 'Saturday':
case 'Sunday':
console.log('Weekend!');
break;
default:
console.log('Unknown day');
}
// → 'Weekday — work day'
Key rules for switch:
breakexits the switch. Without it, execution "falls through" to the next case.defaultruns if no case matches (like an else).- Switch uses strict equality (
===) for comparisons. - Multiple cases can share the same block (stacking cases without
breakin between).
2.6 Fall-through (deliberate vs accidental)
// Deliberate fall-through (stacked cases)
switch (season) {
case 'spring':
case 'summer':
console.log('Warm season');
break;
case 'autumn':
case 'winter':
console.log('Cold season');
break;
}
// Accidental fall-through (missing break — BUG)
switch (x) {
case 1:
console.log('one');
// forgot break! falls through to case 2
case 2:
console.log('two');
break;
}
// If x is 1: prints 'one' AND 'two' — usually not intended
2.7 Guard clauses (early returns)
Instead of nesting conditions inside each other, return early from a function as soon as a condition fails. This keeps the "happy path" unindented and easier to read.
// Deeply nested — hard to read
function processOrder(user, cart) {
if (user) {
if (user.isVerified) {
if (cart.length > 0) {
console.log('Processing order...');
} else {
console.log('Cart is empty');
}
} else {
console.log('User not verified');
}
} else {
console.log('No user');
}
}
// With guard clauses — flat and readable
function processOrder(user, cart) {
if (!user) return console.log('No user');
if (!user.isVerified) return console.log('User not verified');
if (cart.length === 0) return console.log('Cart is empty');
console.log('Processing order...'); // happy path
}
2.8 Truthy/falsy in conditions
Because JavaScript converts conditions to booleans, you can write concise checks:
const name = 'Alice';
const items = [];
const user = null;
if (name) { console.log('Name is set'); } // runs — 'Alice' is truthy
if (!items.length) { console.log('Empty'); } // runs — 0 is falsy
if (!user) { console.log('No user'); } // runs — null is falsy
// Equivalent verbose versions
if (name !== '') { ... }
if (items.length === 0) { ... }
if (user === null || user === undefined) { ... }
3. Real World Example
// User authentication flow
function handleLogin(username, password) {
// Guard clauses first
if (!username || !password) {
return 'Please fill in all fields.';
}
if (username.length < 3) {
return 'Username must be at least 3 characters.';
}
if (password.length < 8) {
return 'Password must be at least 8 characters.';
}
// Simulate checking credentials
if (username === 'admin' && password === 'secret123') {
return 'Welcome back, Admin!';
} else if (username === 'guest') {
return 'Logged in as guest.';
} else {
return 'Invalid credentials.';
}
}
console.log(handleLogin('', 'pass')); // 'Please fill in all fields.'
console.log(handleLogin('al', 'password')); // 'Username must be...'
console.log(handleLogin('admin', 'secret123')); // 'Welcome back, Admin!'
console.log(handleLogin('bob', 'wrongpass')); // 'Invalid credentials.'
4. Code Example
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Conditions Demo</title></head>
<body>
<h1>Traffic Light</h1>
<input type="text" id="colour-input" placeholder="Enter: red, yellow, or green">
<button id="check-btn">Check</button>
<p id="result"></p>
<script>
function getInstruction(colour) {
// Guard clause
if (!colour) return 'Please enter a colour.';
// Normalise input
const c = colour.trim().toLowerCase();
// switch — clean for discrete string options
switch (c) {
case 'red':
return 'Stop!';
case 'yellow':
return 'Prepare to stop.';
case 'green':
return 'Go!';
default:
return `'${c}' is not a valid traffic light colour.`;
}
}
document.querySelector('#check-btn').addEventListener('click', () => {
const input = document.querySelector('#colour-input').value;
const result = document.querySelector('#result');
const msg = getInstruction(input);
result.textContent = msg;
// if/else to set the colour of the result text
if (input.trim().toLowerCase() === 'red') {
result.style.color = 'red';
} else if (input.trim().toLowerCase() === 'yellow') {
result.style.color = 'goldenrod';
} else if (input.trim().toLowerCase() === 'green') {
result.style.color = 'green';
} else {
result.style.color = 'black';
}
});
</script>
</body>
</html>
5. Code Breakdown
Guard clause (if !colour return)
The first thing the function does is check for an empty input and exit immediately. This means the rest of the function only runs with valid data — no wrapping the whole body in an extra if block.
colour.trim().toLowerCase()
Chaining string methods: trim() removes surrounding whitespace, toLowerCase() makes the comparison case-insensitive. Users can type "Red", "RED", or " red " and it still matches.
switch vs if/else chains
The switch is cleaner than an if / else if / else if chain when testing a single variable against several exact values. When the conditions involve ranges (e.g., score >= 80), use if/else if.
if/else for colour styling
After the switch returns a message, a separate if/else controls the visual style. This is a separation of concerns — the function returns the message, and the event handler applies UI changes. You could also use a lookup object here (covered in Module 12).
6. Common Mistakes
Mistake 1 — Missing break in switch
switch (x) {
case 1:
console.log('one'); // FALLS THROUGH
case 2:
console.log('two'); // also runs when x === 1!
break;
}
Mistake 2 — Putting less specific conditions first
// Bug — score 95 matches the first condition and gets 'Pass'
if (score >= 50) {
return 'Pass';
} else if (score >= 90) {
return 'Distinction'; // never reached!
}
// Correct — more specific first
if (score >= 90) {
return 'Distinction';
} else if (score >= 50) {
return 'Pass';
}
Mistake 3 — Using = instead of === in if condition
if (x = 0) { ... } // assigns 0, condition is always falsy
if (x === 0) { ... } // correct comparison
Mistake 4 — Deep nesting instead of guard clauses
Three or more levels of nesting makes code very hard to follow. Flatten by returning early or extracting into helper functions.
Mistake 5 — Comparing strings with == in switch
Switch uses === internally. switch('5') will NOT match case 5: (string vs number). Make sure your types match.
7. Best Practices
- Use guard clauses to handle invalid inputs at the top of functions — keeps the main logic flat.
- Always include a default case in switch statements.
- Never forget break in switch cases unless fall-through is intentional — comment it when intentional.
- Put more specific conditions first in if/else if chains.
- Prefer switch for many exact-value comparisons of one variable; prefer if/else if for range or complex conditions.
- Normalise input early (trim, toLowerCase) before comparing strings.
- Keep condition logic readable — extract complex boolean expressions into named variables:
const isEligible = age >= 18 && hasId; - Avoid else after a return — if the if block returns, the else is unnecessary.
8. Practice Exercise
- Write a function
bmi(weight, height)that calculates BMI (weight / height²) and returns a string: 'Underweight' (<18.5), 'Normal' (18.5–24.9), 'Overweight' (25–29.9), or 'Obese' (>=30). - Write a function
fizzBuzz(n)that returns 'FizzBuzz' if divisible by both 3 and 5, 'Fizz' if by 3, 'Buzz' if by 5, or the number as a string otherwise. (Hint: check the most specific case first.) - Write a
getSeasonMessage(month)function using a switch that returns a short message for each month (e.g., 'January — bundle up!' etc.). Group month numbers into seasons.
Bonus
- Build an interactive temperature converter: input a number and select Celsius/Fahrenheit. On button click, show the converted value with an if/else to choose the correct formula.
9. Assignment
Build a "Movie Rating System."
- Create an HTML page with inputs for: movie title (text), genre (select: Action, Comedy, Horror, Drama), runtime in minutes (number), and user rating (1–10).
- On form submit, validate all fields using guard clauses (no empty title, valid rating range).
- Use a switch on genre to assign a genre icon/emoji.
- Use if/else if to classify the runtime: 'Short' (<90 min), 'Standard' (90–150), 'Long' (>150).
- Use if/else to classify the rating: 'Must Watch' (9–10), 'Great' (7–8), 'OK' (5–6), 'Skip' (<5).
- Display a formatted summary card on the page.
Deliverable: One HTML file. All logic in JavaScript.
10. Interview Questions
- What is the difference between if/else if and switch?
Both implement branching. switch is cleaner for testing a single variable against many exact values. if/else if is more flexible — it can handle range comparisons, multiple variables, and complex conditions. switch uses strict equality (===). - What happens if you forget a break in a switch case?
Execution "falls through" to the next case and runs it too, regardless of whether it matches. This is usually a bug. Fall-through can be used intentionally to share code between cases, but should be commented. - What is a guard clause?
An early return at the top of a function that handles edge cases (invalid input, missing data) immediately, so the main logic runs without extra nesting. Makes functions easier to read and test. - How does JavaScript evaluate the condition in an if statement?
It converts the condition to a boolean. Falsy values (false, 0, '', null, undefined, NaN) cause the if block to be skipped. Everything else is truthy and runs the block. - When would you choose ternary over if/else?
When you need a simple two-option value (not a side effect), and both options are short. For multi-branch logic, complex conditions, or side effects, use if/else for readability.
11. Additional Resources
- MDN — if...else
- MDN — switch
- javascript.info — Conditional branching: if, ?
- javascript.info — switch statement