Chapter 5: JS Control Flow & Conditions
Control flow allows your JavaScript code to make decisions, execute alternative paths, validate user permissions, and handle different states using if / else if / else statements, multi-branch switch constructs, truthy vs falsy conversions, and guard clauses.
5.1 The if, else if, and else Statements
The if statement executes a block of code if a specified condition evaluates to true. An optional else if tests secondary conditions if the first condition is false, and else catches all other remaining cases.
Grading System: Multi-Branch If/Else
function evaluateGrade(score) {
if (score >= 90) {
return "A+ (Outstanding Mastery)";
} else if (score >= 80) {
return "A (Excellent Performance)";
} else if (score >= 70) {
return "B (Good Understanding)";
} else if (score >= 60) {
return "C (Passing)";
} else {
return "F (Needs Practice & Retest)";
}
}
console.log(evaluateGrade(88)); // "A (Excellent Performance)"
console.log(evaluateGrade(45)); // "F (Needs Practice & Retest)"
Try in Playground »
5.2 The switch Statement & Fall-Through Behavior
The switch statement evaluates an expression against multiple matching case clauses using strict equality (===). If a match is found, code executes until a break statement is encountered.
Always Include the break Keyword!
If you omit break, execution will "fall through" and execute all subsequent cases unconditionally regardless of whether their condition matches, until the switch block ends.
Switch Statement with Strict Type Matching
function getRolePermissions(role) {
switch (role) {
case "admin":
case "superadmin": // Grouped cases (Fall-through by design)
return "Full Access: Read, Write, Delete, Manage Users";
case "editor":
return "Editor Access: Read, Create, Edit Posts";
case "subscriber":
return "Read-Only Access: View Articles & Comment";
default: // Executed if no cases match
return "Guest Access: View Public Pages Only";
}
}
console.log(getRolePermissions("admin")); // Full Access
console.log(getRolePermissions("guest")); // Guest Access: View Public Pages Only
JavaScript executes conditional branches from top to bottom, immediately halting evaluation once the first matching branch executes.
5.4 Truthy vs Falsy Values in JavaScript
In JavaScript, when a non-boolean value is evaluated in a boolean context (such as an if (condition)), it is automatically coerced into either true or false.
There are exactly 8 falsy values in all of JavaScript:
false(the boolean literal)0and-0(the number zero)0n(BigInt zero)""or''(empty string)null(absence of value)undefined(uninitialized)NaN(Not-a-Number)document.all(legacy browser exception)
ANY value that is NOT in the 8 falsy list is truthy, including:
"0"(string containing zero!)"false"(string containing false!)[](empty array is an object!){}(empty object is truthy!)function() {}(functions are truthy)-10,3.14(any non-zero number)Infinity/-Infinity
5.5 Clean Architecture: Guard Clauses vs Nested Pyramid of Doom
A Guard Clause is an early return inside a function that checks for invalid inputs, errors, or missing permissions at the very beginning of the function, eliminating deeply nested if/else pyramids.
Nested Pyramid of Doom (Bad)
function processPayment(user, cart) {
if (user) {
if (user.isLoggedIn) {
if (cart.length > 0) {
if (user.hasFunds) {
return "Payment Processed!";
}
}
}
}
return "Payment Failed";
}
Clean Guard Clauses (Recommended Standard)
function processPayment(user, cart) {
// Early returns for failure states
if (!user?.isLoggedIn) return "Please login";
if (!cart?.length) return "Cart is empty";
if (!user.hasFunds) return "Insufficient funds";
// Happy path cleanly at the root level!
return "Payment Processed!";
}
5.6 Live Truthy / Falsy & Condition Tester
Live Sandbox
Test how JavaScript's condition engine evaluates different values in an if (expression) statement.
5.7 Hands-on Challenge: Role-Based Security Gatekeeper
Write a security gatekeeper function authorizeAccess(user, action) using clean Guard Clauses and a switch statement that grants or denies access based on the user's role and account status.
Requirements:
- Use Guard Clauses: If
!useror!user.isActive, return"Access Denied: Inactive or Invalid Account". - If
user.isBannedis true, return"Access Denied: Account Banned". - Use a
switch (user.role):"admin": Has access to all actions ("Access Granted: Admin Full Privileges")."editor": Can"create"or"edit", but not"delete"."viewer": Can only"read".default: Return"Access Denied: Unrecognized Role".
Need a Hint?
if (!user?.isActive) return ...; and if (user.isBanned) return ...;. Then structure your switch statement with switch (user.role) { case "admin": return ...; ... }.
Reveal Full Solution
function authorizeAccess(user, action) {
// 1. Guard Clauses for invalid / banned accounts
if (!user || !user.isActive) {
return "Access Denied: Inactive or Invalid Account";
}
if (user.isBanned) {
return "Access Denied: Account Banned";
}
// 2. Role-Based Permissions
switch (user.role) {
case "admin":
return `Access Granted: Admin authorized for "${action}"`;
case "editor":
if (action === "create" || action === "edit" || action === "read") {
return `Access Granted: Editor authorized for "${action}"`;
}
return `Access Denied: Editors cannot perform "${action}"`;
case "viewer":
if (action === "read") {
return `Access Granted: Viewer authorized for "${action}"`;
}
return `Access Denied: Viewers can only read content`;
default:
return "Access Denied: Unrecognized Role";
}
}
// Test Case 1: Active Editor creating a post
console.log(authorizeAccess({ role: "editor", isActive: true, isBanned: false }, "create"));
// Output: "Access Granted: Editor authorized for \"create\""
// Test Case 2: Banned user attempting read
console.log(authorizeAccess({ role: "admin", isActive: true, isBanned: true }, "read"));
// Output: "Access Denied: Account Banned"
▶ Run Solution in Playground »