JavaScript Control Statements: Complete Guide for Developers
Master JavaScript control flow: if-else, switch, loops (for, while, do-while, for-of, for-in), break, continue, and advanced patterns with detailed examples.
JavaScript Control Statements: Complete Guide for Developers
📋 Table of Contents
- What are Control Statements?
- Why Do We Need Control Statements?
- Real-World Use Cases
- Syntax
- Internal Working
- Memory Diagram
- Data Flow Diagram
- Code Examples
- Common Mistakes
- Performance Considerations
- Interview Questions
- Cheat Sheet
- Summary
1. What are Control Statements?
Control statements determine the flow of program execution. They allow you to make decisions, repeat actions, and control the order in which code executes.
Control Flow Categories
┌─────────────────────────────────────────────────────────────┐
│ JAVASCRIPT CONTROL STATEMENTS │
└─────────────────────────────────────────────────────────────┘
Control Statements
|
┌────┴────────────────────────┐
| |
├─ Conditional Statements
| • if
| • if-else
| • if-else-if
| • switch
| • Ternary operator (? :)
|
├─ Loop Statements
| • for
| • while
| • do-while
| • for...of (ES6)
| • for...in
| • forEach (array method)
|
└─ Jump Statements
• break
• continue
• return
• throw
Sequential vs Controlled Execution
┌─────────────────────────────────────────────────────────────┐
│ EXECUTION FLOW │
└─────────────────────────────────────────────────────────────┘
Sequential (No Control):
────────────────────────
Statement 1
↓
Statement 2
↓
Statement 3
↓
Statement 4
Controlled (With Decisions):
────────────────────────────
Statement 1
↓
Condition?
├─ true → Statement 2
└─ false → Statement 3
↓
Statement 4
2. Why Do We Need Control Statements?
Control statements enable dynamic, responsive applications.
Without Control Statements
// Static, inflexible code
console.log("Welcome");
console.log("Processing payment");
console.log("Order confirmed");
// Always executes the same way
With Control Statements
// Dynamic, responsive code
if (isLoggedIn) {
console.log("Welcome back!");
if (hasItems) {
processPayment();
confirmOrder();
} else {
console.log("Your cart is empty");
}
} else {
redirectToLogin();
}
3. Real-World Use Cases
1. User Authentication
function authenticate(username, password) {
if (!username || !password) {
return { success: false, message: "Missing credentials" };
}
if (username === "admin" && password === "secret") {
return { success: true, message: "Welcome Admin" };
} else {
return { success: false, message: "Invalid credentials" };
}
}
2. Form Validation
function validateForm(data) {
const errors = [];
if (!data.email || !data.email.includes('@')) {
errors.push("Invalid email");
}
if (!data.password || data.password.length < 8) {
errors.push("Password must be at least 8 characters");
}
if (data.age && data.age < 18) {
errors.push("Must be 18 or older");
}
return errors.length === 0 ? { valid: true } : { valid: false, errors };
}
3. Data Processing
function processOrders(orders) {
for (const order of orders) {
switch (order.status) {
case 'pending':
processPendingOrder(order);
break;
case 'shipped':
updateTracking(order);
break;
case 'delivered':
sendConfirmation(order);
break;
default:
logUnknownStatus(order);
}
}
}
4. Syntax
Conditional Statements
// ═══════════════════════════════════════════════════════════
// IF STATEMENT
// ═══════════════════════════════════════════════════════════
if (condition) {
// Execute if condition is true
}
// Example
const age = 20;
if (age >= 18) {
console.log("Adult");
}
// ═══════════════════════════════════════════════════════════
// IF-ELSE STATEMENT
// ═══════════════════════════════════════════════════════════
if (condition) {
// Execute if true
} else {
// Execute if false
}
// Example
if (age >= 18) {
console.log("Adult");
} else {
console.log("Minor");
}
// ═══════════════════════════════════════════════════════════
// IF-ELSE-IF LADDER
// ═══════════════════════════════════════════════════════════
if (condition1) {
// Execute if condition1 is true
} else if (condition2) {
// Execute if condition2 is true
} else if (condition3) {
// Execute if condition3 is true
} else {
// Execute if all conditions are false
}
// Example
const score = 85;
if (score >= 90) {
console.log("Grade: A");
} else if (score >= 80) {
console.log("Grade: B");
} else if (score >= 70) {
console.log("Grade: C");
} else {
console.log("Grade: F");
}
// ═══════════════════════════════════════════════════════════
// NESTED IF
// ═══════════════════════════════════════════════════════════
if (condition1) {
if (condition2) {
// Execute if both conditions are true
}
}
// Example
const isLoggedIn = true;
const hasPermission = true;
if (isLoggedIn) {
if (hasPermission) {
console.log("Access granted");
}
}
// ═══════════════════════════════════════════════════════════
// SWITCH STATEMENT
// ═══════════════════════════════════════════════════════════
switch (expression) {
case value1:
// Execute if expression === value1
break;
case value2:
// Execute if expression === value2
break;
default:
// Execute if no case matches
}
// Example
const day = 2;
switch (day) {
case 1:
console.log("Monday");
break;
case 2:
console.log("Tuesday");
break;
case 3:
console.log("Wednesday");
break;
default:
console.log("Invalid day");
}
Loop Statements
// ═══════════════════════════════════════════════════════════
// FOR LOOP
// ═══════════════════════════════════════════════════════════
for (initialization; condition; increment) {
// Execute while condition is true
}
// Example
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
// ═══════════════════════════════════════════════════════════
// WHILE LOOP
// ═══════════════════════════════════════════════════════════
while (condition) {
// Execute while condition is true
}
// Example
let count = 0;
while (count < 5) {
console.log(count);
count++;
}
// ═══════════════════════════════════════════════════════════
// DO-WHILE LOOP
// ═══════════════════════════════════════════════════════════
do {
// Execute at least once
} while (condition);
// Example
let num = 10;
do {
console.log(num); // Prints 10 (even though condition is false)
} while (num < 5);
// ═══════════════════════════════════════════════════════════
// FOR...OF LOOP (ES6)
// ═══════════════════════════════════════════════════════════
for (const element of iterable) {
// Iterate over values
}
// Example
const fruits = ["apple", "banana", "orange"];
for (const fruit of fruits) {
console.log(fruit);
}
// ═══════════════════════════════════════════════════════════
// FOR...IN LOOP
// ═══════════════════════════════════════════════════════════
for (const key in object) {
// Iterate over keys
}
// Example
const user = { name: "John", age: 30, city: "NYC" };
for (const key in user) {
console.log(`${key}: ${user[key]}`);
}
Jump Statements
// ═══════════════════════════════════════════════════════════
// BREAK
// ═══════════════════════════════════════════════════════════
for (let i = 0; i < 10; i++) {
if (i === 5) {
break; // Exit loop
}
console.log(i); // 0, 1, 2, 3, 4
}
// ═══════════════════════════════════════════════════════════
// CONTINUE
// ═══════════════════════════════════════════════════════════
for (let i = 0; i < 5; i++) {
if (i === 2) {
continue; // Skip this iteration
}
console.log(i); // 0, 1, 3, 4
}
// ═══════════════════════════════════════════════════════════
// RETURN
// ═══════════════════════════════════════════════════════════
function findUser(id) {
const users = [{ id: 1 }, { id: 2 }, { id: 3 }];
for (const user of users) {
if (user.id === id) {
return user; // Exit function
}
}
return null;
}
5. Internal Working
Conditional Statement Evaluation
┌─────────────────────────────────────────────────────────────┐
│ IF-ELSE EVALUATION │
└─────────────────────────────────────────────────────────────┘
Code:
─────
if (age >= 18) {
console.log("Adult");
} else {
console.log("Minor");
}
Evaluation Process:
───────────────────
1. Evaluate condition: age >= 18
2. Convert to boolean (if needed)
3. If true:
- Execute if block
- Skip else block
4. If false:
- Skip if block
- Execute else block
Truth Table:
────────────
age = 20 → age >= 18 → true → "Adult"
age = 15 → age >= 18 → false → "Minor"
Switch Statement Evaluation
┌─────────────────────────────────────────────────────────────┐
│ SWITCH EVALUATION │
└─────────────────────────────────────────────────────────────┘
Code:
─────
switch (day) {
case 1:
console.log("Monday");
break;
case 2:
console.log("Tuesday");
break;
default:
console.log("Other");
}
Evaluation Process:
───────────────────
1. Evaluate expression: day
2. Compare with case 1 using === (strict equality)
3. If match:
- Execute case block
- If break: exit switch
- If no break: fall through to next case
4. If no match:
- Try next case
5. If no cases match:
- Execute default (if present)
Important: Uses === (strict equality)
day = 1 → Matches case 1
day = "1" → No match (different type)
Loop Execution
┌─────────────────────────────────────────────────────────────┐
│ FOR LOOP EXECUTION │
└─────────────────────────────────────────────────────────────┘
Code:
─────
for (let i = 0; i < 3; i++) {
console.log(i);
}
Execution Steps:
────────────────
Step 1: Initialize (let i = 0)
i = 0
Step 2: Check condition (i < 3)
0 < 3 → true → Execute body
Step 3: Execute body
console.log(0)
Step 4: Increment (i++)
i = 1
Step 5: Check condition (i < 3)
1 < 3 → true → Execute body
Step 6: Execute body
console.log(1)
Step 7: Increment (i++)
i = 2
Step 8: Check condition (i < 3)
2 < 3 → true → Execute body
Step 9: Execute body
console.log(2)
Step 10: Increment (i++)
i = 3
Step 11: Check condition (i < 3)
3 < 3 → false → Exit loop
Output: 0, 1, 2
6. Memory Diagram
┌─────────────────────────────────────────────────────────────┐
│ LOOP VARIABLE MEMORY │
└─────────────────────────────────────────────────────────────┘
for (let i = 0; i < 3; i++) {
console.log(i);
}
Memory During Execution:
────────────────────────
Iteration 1:
┌──────────────┐
│ Stack │
├──────────────┤
│ i: 0 │ ← Loop variable
└──────────────┘
Iteration 2:
┌──────────────┐
│ Stack │
├──────────────┤
│ i: 1 │ ← Updated
└──────────────┘
Iteration 3:
┌──────────────┐
│ Stack │
├──────────────┤
│ i: 2 │ ← Updated
└──────────────┘
After Loop:
┌──────────────┐
│ Stack │
├──────────────┤
│ (i removed) │ ← Block scope ended
└──────────────┘
┌─────────────────────────────────────────────────────────────┐
│ NESTED LOOP MEMORY │
└─────────────────────────────────────────────────────────────┘
for (let i = 0; i < 2; i++) {
for (let j = 0; j < 2; j++) {
console.log(i, j);
}
}
Memory Layout:
──────────────
┌──────────────┐
│ Stack │
├──────────────┤
│ i: 0 │ ← Outer loop
│ j: 0 │ ← Inner loop
└──────────────┘
Execution:
(0, 0) → (0, 1) → (1, 0) → (1, 1)
7. Data Flow Diagram
┌─────────────────────────────────────────────────────────────┐
│ IF-ELSE FLOW │
└─────────────────────────────────────────────────────────────┘
Start
↓
┌──────────┐
│Condition?│
└──────────┘
↙ ↘
true false
↓ ↓
┌────────┐ ┌────────┐
│ if │ │ else │
│ block │ │ block │
└────────┘ └────────┘
↓ ↓
└────┬───┘
↓
End
┌─────────────────────────────────────────────────────────────┐
│ SWITCH FLOW │
└─────────────────────────────────────────────────────────────┘
Start
↓
Expression
↓
┌───────┐
│Case 1?│
└───────┘
↙ ↘
Yes No
↓ ↓
Execute ┌───────┐
↓ │Case 2?│
break └───────┘
↓ ↙ ↘
│ Yes No
│ ↓ ↓
│ Execute default
│ ↓ ↓
│ break Execute
│ ↓ ↓
└──────┴───────┘
↓
End
┌─────────────────────────────────────────────────────────────┐
│ FOR LOOP FLOW │
└─────────────────────────────────────────────────────────────┘
Start
↓
Initialize
↓
┌──────────┐
│Condition?│
└──────────┘
↙ ↘
true false
↓ ↓
Execute End
Body
↓
Increment
↓
└──→ (back to Condition)
┌─────────────────────────────────────────────────────────────┐
│ BREAK vs CONTINUE │
└─────────────────────────────────────────────────────────────┘
break:
──────
Loop → Condition → Execute → break → Exit Loop
continue:
─────────
Loop → Condition → Execute → continue → Skip Rest → Next Iteration
8. Code Examples
Example 1: Grade Calculator
function calculateGrade(score) {
if (score < 0 || score > 100) {
return "Invalid score";
}
if (score >= 90) {
return "A";
} else if (score >= 80) {
return "B";
} else if (score >= 70) {
return "C";
} else if (score >= 60) {
return "D";
} else {
return "F";
}
}
console.log(calculateGrade(95)); // "A"
console.log(calculateGrade(75)); // "C"
console.log(calculateGrade(55)); // "F"
Example 2: User Role Authorization
function checkAccess(role, resource) {
switch (role) {
case "admin":
return "Full access to " + resource;
case "editor":
if (resource === "content") {
return "Edit access to " + resource;
}
return "Read-only access to " + resource;
case "viewer":
return "Read-only access to " + resource;
default:
return "No access";
}
}
console.log(checkAccess("admin", "database")); // "Full access to database"
console.log(checkAccess("editor", "content")); // "Edit access to content"
console.log(checkAccess("viewer", "reports")); // "Read-only access to reports"
Example 3: Array Processing
// Find first even number
function findFirstEven(numbers) {
for (const num of numbers) {
if (num % 2 === 0) {
return num; // Exit function when found
}
}
return null; // Not found
}
console.log(findFirstEven([1, 3, 5, 8, 9])); // 8
// Sum only positive numbers
function sumPositive(numbers) {
let sum = 0;
for (const num of numbers) {
if (num <= 0) {
continue; // Skip negative and zero
}
sum += num;
}
return sum;
}
console.log(sumPositive([1, -2, 3, -4, 5])); // 9
// Process until condition met
function processUntilLimit(items, limit) {
let processed = 0;
for (const item of items) {
if (processed >= limit) {
break; // Stop when limit reached
}
console.log(`Processing: ${item}`);
processed++;
}
return processed;
}
processUntilLimit(["a", "b", "c", "d", "e"], 3);
// Processes: a, b, c
Example 4: Nested Loops - Matrix Operations
// Print multiplication table
function multiplicationTable(size) {
for (let i = 1; i <= size; i++) {
let row = "";
for (let j = 1; j <= size; j++) {
row += (i * j).toString().padStart(4, " ");
}
console.log(row);
}
}
multiplicationTable(5);
/*
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
*/
// Find pair with target sum
function findPairWithSum(arr, target) {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] + arr[j] === target) {
return [arr[i], arr[j]];
}
}
}
return null;
}
console.log(findPairWithSum([1, 2, 3, 4, 5], 7)); // [2, 5] or [3, 4]
Example 5: Loop Comparison
const numbers = [1, 2, 3, 4, 5];
// for loop (traditional)
console.log("for loop:");
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}
// while loop
console.log("while loop:");
let i = 0;
while (i < numbers.length) {
console.log(numbers[i]);
i++;
}
// do-while loop
console.log("do-while loop:");
let j = 0;
do {
console.log(numbers[j]);
j++;
} while (j < numbers.length);
// for...of loop (modern, clean)
console.log("for...of loop:");
for (const num of numbers) {
console.log(num);
}
// forEach (array method)
console.log("forEach:");
numbers.forEach(num => console.log(num));
9. Common Mistakes
Mistake 1: Missing break in switch
// ❌ Wrong: Missing break causes fall-through
const day = 1;
switch (day) {
case 1:
console.log("Monday");
case 2:
console.log("Tuesday");
case 3:
console.log("Wednesday");
}
// Output: Monday, Tuesday, Wednesday (all three!)
// ✅ Correct: Use break
switch (day) {
case 1:
console.log("Monday");
break;
case 2:
console.log("Tuesday");
break;
case 3:
console.log("Wednesday");
break;
}
// Output: Monday
Mistake 2: Infinite Loops
// ❌ Wrong: Infinite loop (forgot to increment)
let i = 0;
while (i < 5) {
console.log(i);
// Missing: i++
}
// ✅ Correct: Proper increment
let i = 0;
while (i < 5) {
console.log(i);
i++;
}
Mistake 3: Using for...in with Arrays
const arr = [10, 20, 30];
// ❌ Wrong: for...in gives indices (and can include prototype properties)
for (const index in arr) {
console.log(index); // "0", "1", "2" (strings!)
}
// ✅ Correct: for...of gives values
for (const value of arr) {
console.log(value); // 10, 20, 30
}
Mistake 4: Modifying Array While Iterating
// ❌ Wrong: Modifying array during iteration
const numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
numbers.splice(i, 1); // Skips elements!
}
}
// ✅ Correct: Iterate backwards or use filter
const numbers = [1, 2, 3, 4, 5];
for (let i = numbers.length - 1; i >= 0; i--) {
if (numbers[i] % 2 === 0) {
numbers.splice(i, 1);
}
}
// ✅ Better: Use filter
const numbers = [1, 2, 3, 4, 5];
const oddNumbers = numbers.filter(n => n % 2 !== 0);
Mistake 5: Confusing Assignment with Comparison
// ❌ Wrong: Assignment instead of comparison
let x = 5;
if (x = 10) { // Assigns 10 to x, always true!
console.log("This always runs");
}
console.log(x); // 10 (modified!)
// ✅ Correct: Use comparison
let x = 5;
if (x === 10) { // Comparison
console.log("This doesn't run");
}
console.log(x); // 5 (unchanged)
10. Performance Considerations
1. Loop Performance
const arr = new Array(1000000).fill(1);
// ✅ Fastest: Traditional for loop
console.time("for");
for (let i = 0; i < arr.length; i++) {
arr[i] * 2;
}
console.timeEnd("for");
// ✅ Fast: for...of
console.time("for...of");
for (const item of arr) {
item * 2;
}
console.timeEnd("for...of");
// ❌ Slower: forEach
console.time("forEach");
arr.forEach(item => item * 2);
console.timeEnd("forEach");
2. Cache Array Length
// ❌ Slow: Recalculates length every iteration
for (let i = 0; i < array.length; i++) {
// process
}
// ✅ Fast: Cache length
const len = array.length;
for (let i = 0; i < len; i++) {
// process
}
3. Avoid Nested Loops When Possible
// ❌ Slow: O(n²) complexity
function findDuplicates(arr) {
const duplicates = [];
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
duplicates.push(arr[i]);
}
}
}
return duplicates;
}
// ✅ Fast: O(n) complexity using Set
function findDuplicates(arr) {
const seen = new Set();
const duplicates = new Set();
for (const item of arr) {
if (seen.has(item)) {
duplicates.add(item);
}
seen.add(item);
}
return Array.from(duplicates);
}
11. Interview Questions
Q1: What's the difference between for and while loops?
Answer:
- for: Best when you know the number of iterations. Initialization, condition, and increment are in one line.
- while: Best when iterations depend on a condition that may change unpredictably.
// for: Known iterations
for (let i = 0; i < 10; i++) { }
// while: Unknown iterations
while (dataAvailable()) { }
Q2: What's the difference between for...of and for...in?
Answer:
- for...of: Iterates over values of iterables (arrays, strings, Map, Set)
- for...in: Iterates over enumerable property keys of objects
const arr = [10, 20, 30];
for (const value of arr) {
console.log(value); // 10, 20, 30
}
for (const index in arr) {
console.log(index); // "0", "1", "2"
}
Q3: What's the difference between break and continue?
Answer:
- break: Exits the entire loop immediately
- continue: Skips the current iteration and continues with the next
for (let i = 0; i < 5; i++) {
if (i === 2) break;
console.log(i); // 0, 1
}
for (let i = 0; i < 5; i++) {
if (i === 2) continue;
console.log(i); // 0, 1, 3, 4
}
Q4: When should you use switch instead of if-else?
Answer: Use switch when:
- Comparing a single variable against multiple specific values
- Values are discrete (not ranges)
- Need better readability for many conditions
// Better with switch
switch (status) {
case 'pending': // ...
case 'approved': // ...
case 'rejected': // ...
}
// Better with if-else
if (age < 18) { }
else if (age < 65) { }
else { }
Q5: What is fall-through in switch statements?
Answer: Fall-through occurs when a case doesn't have a break statement, causing execution to continue into the next case.
switch (grade) {
case 'A':
case 'B':
console.log("Pass"); // Both A and B execute this
break;
case 'F':
console.log("Fail");
break;
}
Q6: Which loop executes at least once?
Answer: The do-while loop executes at least once because the condition is checked after the first execution.
let x = 10;
do {
console.log(x); // Prints 10
} while (x < 5); // Condition is false, but already executed once
12. Cheat Sheet
// ═══════════════════════════════════════════════════════════
// CONTROL STATEMENTS QUICK REFERENCE
// ═══════════════════════════════════════════════════════════
// CONDITIONAL STATEMENTS
// ──────────────────────
if (condition) { }
if (condition) { } else { }
if (cond1) { } else if (cond2) { } else { }
switch (expr) { case val: break; default: }
// LOOPS
// ─────
for (let i = 0; i < n; i++) { } // Known iterations
while (condition) { } // Unknown iterations
do { } while (condition); // Execute at least once
for (const item of array) { } // Array values
for (const key in object) { } // Object keys
// JUMP STATEMENTS
// ───────────────
break; // Exit loop/switch
continue; // Skip iteration
return value; // Exit function
// BEST PRACTICES
// ──────────────
✓ Use for...of for arrays
✓ Use for...in for objects
✓ Always use break in switch (unless intentional fall-through)
✓ Cache array length in loops
✓ Use meaningful variable names
✓ Avoid deep nesting (max 3 levels)
✗ Don't modify arrays while iterating
✗ Don't use for...in with arrays
✗ Don't create infinite loops
✗ Don't forget break in switch
// LOOP COMPARISON
// ───────────────
for → Best performance, known iterations
while → Unknown iterations
do-while → Execute at least once
for...of → Clean syntax for arrays
for...in → Object properties
forEach → Functional style (can't break)
// PERFORMANCE TIPS
// ────────────────
• Cache array.length
• Avoid nested loops when possible
• Use break to exit early
• Consider Set/Map for lookups
• Profile before optimizing
13. Summary
Key Takeaways
✅ Control statements determine program flow
✅ if-else for binary decisions
✅ switch for multiple discrete values
✅ for loop for known iterations
✅ while loop for unknown iterations
✅ do-while executes at least once
✅ for...of for array values
✅ for...in for object keys
✅ break exits loops/switch
✅ continue skips iterations
Best Practices
- Use appropriate control structure for the task
- Keep nesting shallow (max 3 levels)
- Always use break in switch (unless intentional)
- Use for...of for arrays, for...in for objects
- Cache array length in performance-critical loops
- Avoid modifying collections while iterating
- Use meaningful variable names
- Consider early returns to reduce nesting
- Profile before optimizing loops
- Use modern syntax (for...of) when possible
Mastering control statements is essential for writing efficient, readable, and maintainable JavaScript code.