Control Flow
if/else, switch, and ternary โ the tools that let your code make decisions.
if / else if / else
The most fundamental control structure. Execute different code based on conditions:
const score = 75;
if (score >= 90) {
console.log("A โ Excellent!");
} else if (score >= 80) {
console.log("B โ Good");
} else if (score >= 70) {
console.log("C โ Average");
} else if (score >= 60) {
console.log("D โ Below average");
} else {
console.log("F โ Needs improvement");
}
// Output: "C โ Average"
The conditions are evaluated top to bottom. Once one matches, the rest are skipped.
Truthy and Falsy
JavaScript coerces the condition in if to a boolean. Understanding truthy/falsy values is essential:
// Falsy values โ evaluate as false in conditions:
if (!false) console.log("false is falsy");
if (!0) console.log("0 is falsy");
if (!-0) console.log("-0 is falsy");
if (!0n) console.log("0n is falsy");
if (!"") console.log("empty string is falsy");
if (!null) console.log("null is falsy");
if (!undefined) console.log("undefined is falsy");
if (!NaN) console.log("NaN is falsy");
// Everything else is truthy, including:
if ("0") console.log('"0" is truthy!');
if ([]) console.log("[] is truthy!");
if ({}) console.log("{} is truthy!");
โ Tip
A quick way to check if a value is truthy: Boolean(value) or !!value.
switch Statement
switch is cleaner than many if/else chains when comparing a single value against multiple options:
const day = "Monday";
switch (day) {
case "Monday":
case "Tuesday":
case "Wednesday":
case "Thursday":
case "Friday":
console.log("Weekday");
break;
case "Saturday":
case "Sunday":
console.log("Weekend!");
break;
default:
console.log("Unknown day");
}
โ ๏ธDon't forget break!
Without break, execution falls through to the next case. This is rarely what you want and is a common bug. The example above uses multiple cases intentionally (grouping weekdays), but you almost always need break at the end of each case block.
// Fall-through bug example:
const grade = "A";
switch (grade) {
case "A":
console.log("Excellent");
// missing break!
case "B":
console.log("Good");
break;
case "C":
console.log("Average");
break;
}
// Output: "Excellent" then "Good" โ oops!
Ternary Operator
Perfect for simple two-branch conditions in a single expression:
const age = 20;
const message = age >= 18 ? "You can vote" : "Too young to vote";
console.log(message); // "You can vote"
// Great for inline JSX/template values
const buttonLabel = isLoading ? "Loading..." : "Submit";
const cssClass = isActive ? "active" : "inactive";
Avoid nesting ternaries โ they become unreadable fast:
// โ Hard to read
const result = a > b ? (a > c ? a : c) : (b > c ? b : c);
// โ Use if-else instead
let max;
if (a >= b && a >= c) max = a;
else if (b >= c) max = b;
else max = c;
Short-circuit as Conditionals
&& is often used as a concise conditional:
const user = { name: "Alice", isAdmin: true };
// Only call the function if isAdmin is true
user.isAdmin && showAdminPanel();
// React equivalent (render a component conditionally)
// {user.isAdmin && <AdminPanel />}
Logical Assignment Operators (ES2021)
These combine logical operators with assignment:
let a = null;
let b = 0;
let c = "hello";
// Logical OR assignment โ assign if left side is falsy
a ||= "default"; // a = "default" (null is falsy)
b ||= 42; // b = 42 (0 is falsy)
c ||= "other"; // c = "hello" (already truthy)
console.log(a, b, c); // "default", 42, "hello"
// Logical AND assignment โ assign if left side is truthy
let x = 10;
let y = 0;
x &&= 99; // x = 99 (10 is truthy)
y &&= 99; // y = 0 (0 is falsy, no assignment)
console.log(x, y); // 99, 0
// Nullish assignment โ assign only if null/undefined
let config = { timeout: 0 };
config.timeout ??= 3000; // 0 is not null/undefined, stays 0
config.retries ??= 3; // undefined, gets set to 3
console.log(config); // { timeout: 0, retries: 3 }
Early Returns
A clean pattern: handle edge cases first and return early, rather than nesting:
// โ Deeply nested
function processUser(user) {
if (user) {
if (user.isActive) {
if (user.hasPermission) {
return doWork(user);
} else {
return "No permission";
}
} else {
return "Inactive user";
}
} else {
return "No user";
}
}
// โ Early returns โ much cleaner
function processUser(user) {
if (!user) return "No user";
if (!user.isActive) return "Inactive user";
if (!user.hasPermission) return "No permission";
return doWork(user);
}
Key Takeaways
if/else if/elsefor multi-branch decisionsswitchis cleaner for single-value comparisons โ don't forgetbreak- Ternary for simple two-choice inline expressions
- Use early returns to reduce nesting
&&can act as a conditional in expressions
Ready to test your knowledge?
Take a quiz on what you just learned.