Part 4: Control Flow

Directing Program Execution


Conditional Statements

Conditional statements allow your program to make decisions based on conditions.

The if Statement

javascript
const age = 18; if (age >= 18) { console.log('You are an adult'); } // Single statement (braces optional but recommended) if (age >= 18) console.log('Adult'); // Multiple conditions const temperature = 25; if (temperature > 30) { console.log('Hot day!'); console.log('Stay hydrated'); }

The if...else Statement

javascript
const hour = 14; if (hour < 12) { console.log('Good morning'); } else { console.log('Good afternoon'); } // Can be used in expressions (but ternary is cleaner) let greeting; if (hour < 12) { greeting = 'Good morning'; } else { greeting = 'Good afternoon'; } // Better with ternary const greeting2 = hour < 12 ? 'Good morning' : 'Good afternoon';

The else if Chain

javascript
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 if (score >= 60) { console.log('Grade: D'); } else { console.log('Grade: F'); } // Evaluates top to bottom, stops at first true condition const value = 15; if (value > 10) { console.log('Greater than 10'); // This runs } else if (value > 5) { console.log('Greater than 5'); // Skipped even though true }

Nested Conditionals

javascript
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'); } // Can often be simplified with logical operators if (isLoggedIn && isAdmin) { console.log('Welcome, Admin!'); } else if (isLoggedIn) { console.log('Welcome, User!'); } else { console.log('Please log in'); }

Truthy and Falsy in Conditions

javascript
// Falsy values: false, 0, '', null, undefined, NaN const value = ''; if (value) { console.log('Truthy'); } else { console.log('Falsy'); // This runs } // Common patterns const user = null; if (user) { console.log(user.name); // Safe, won't run if user is null } const items = []; if (items.length) { console.log('Has items'); // Won't run for empty array } // Be careful with 0 const count = 0; if (count) { console.log('Has count'); // Won't run even though 0 is valid } // Better if (count !== undefined) { console.log('Count is defined'); }

The switch Statement

Switch statements compare a value against multiple cases.
javascript
const day = 'Monday'; switch (day) { case 'Monday': console.log('Start of work week'); break; case 'Tuesday': case 'Wednesday': case 'Thursday': console.log('Midweek'); break; case 'Friday': console.log('TGIF!'); break; case 'Saturday': case 'Sunday': console.log('Weekend!'); break; default: console.log('Invalid day'); }

The break Statement

javascript
// Without break, execution "falls through" const grade = 'B'; switch (grade) { case 'A': console.log('Excellent!'); // Missing break - falls through! case 'B': console.log('Good job!'); // Missing break - falls through! case 'C': console.log('Well done'); break; default: console.log('Keep trying'); } // Output: 'Good job!' then 'Well done' // Intentional fall-through (document it) switch (grade) { case 'A': case 'B': case 'C': console.log('Passing grade'); break; case 'D': case 'F': console.log('Needs improvement'); break; }

Switch with Expressions

javascript
// Switch uses strict equality (===) const value = '1'; switch (value) { case 1: console.log('Number 1'); break; case '1': console.log('String 1'); // This runs break; } // Switch can be used with expressions const temperature = 35; switch (true) { case temperature < 0: console.log('Freezing'); break; case temperature < 10: console.log('Cold'); break; case temperature < 20: console.log('Cool'); break; case temperature < 30: console.log('Warm'); break; default: console.log('Hot'); }

Object Lookup Alternative

javascript
// Often cleaner than switch for simple mappings const dayMessages = { Monday: 'Start of work week', Tuesday: 'Second day', Wednesday: 'Hump day', Thursday: 'Almost Friday', Friday: 'TGIF!', Saturday: 'Weekend!', Sunday: 'Weekend!' }; const day = 'Friday'; console.log(dayMessages[day] || 'Invalid day');

Loops

Loops repeat code until a condition is met.

The for Loop

javascript
// Basic for loop for (let i = 0; i < 5; i++) { console.log(i); // 0, 1, 2, 3, 4 } // Loop components // for (initialization; condition; update) for (let i = 10; i > 0; i -= 2) { console.log(i); // 10, 8, 6, 4, 2 } // Multiple variables for (let i = 0, j = 10; i < j; i++, j--) { console.log(`i: ${i}, j: ${j}`); } // i: 0, j: 10 // i: 1, j: 9 // ... // i: 4, j: 6 // Infinite loop (be careful!) // for (;;) { console.log('Forever'); } // Iterating arrays const fruits = ['apple', 'banana', 'cherry']; for (let i = 0; i < fruits.length; i++) { console.log(fruits[i]); }

The for...of Loop

javascript
// Iterates over iterable values const colors = ['red', 'green', 'blue']; for (const color of colors) { console.log(color); // red, green, blue } // Works with strings const word = 'Hello'; for (const char of word) { console.log(char); // H, e, l, l, o } // Works with any iterable const set = new Set([1, 2, 3]); for (const value of set) { console.log(value); // 1, 2, 3 } // Getting index with entries() for (const [index, color] of colors.entries()) { console.log(`${index}: ${color}`); } // 0: red // 1: green // 2: blue

The for...in Loop

javascript
// Iterates over enumerable property keys const person = { name: 'Alice', age: 30, city: 'Boston' }; for (const key in person) { console.log(`${key}: ${person[key]}`); } // name: Alice // age: 30 // city: Boston // WARNING: Includes inherited properties function Animal(name) { this.name = name; } Animal.prototype.speak = function() {}; const dog = new Animal('Rex'); for (const key in dog) { console.log(key); // name, speak (inherited!) } // Filter with hasOwnProperty for (const key in dog) { if (dog.hasOwnProperty(key)) { console.log(key); // name (only own properties) } } // Better alternatives for objects Object.keys(person).forEach(key => { console.log(`${key}: ${person[key]}`); }); Object.entries(person).forEach(([key, value]) => { console.log(`${key}: ${value}`); });

The while Loop

javascript
// Basic while loop let count = 0; while (count < 5) { console.log(count); count++; } // Useful when iteration count is unknown function findIndex(array, target) { let i = 0; while (i < array.length) { if (array[i] === target) { return i; } i++; } return -1; } // Reading until condition let input = getInput(); while (input !== 'quit') { processInput(input); input = getInput(); }

The do...while Loop

javascript
// Executes at least once, then checks condition let count = 0; do { console.log(count); count++; } while (count < 5); // Useful for menu-driven programs let choice; do { choice = showMenu(); handleChoice(choice); } while (choice !== 'exit'); // Executes once even if condition is false let x = 10; do { console.log(x); // 10 (runs once) } while (x < 5);

Loop Control

The break Statement

javascript
// Exit loop immediately for (let i = 0; i < 10; i++) { if (i === 5) { break; } console.log(i); // 0, 1, 2, 3, 4 } // Break in while let i = 0; while (true) { if (i >= 5) break; console.log(i++); } // Break only exits innermost loop for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (j === 1) break; console.log(`${i}, ${j}`); } } // 0, 0 // 1, 0 // 2, 0

The continue Statement

javascript
// Skip to next iteration for (let i = 0; i < 5; i++) { if (i === 2) { continue; } console.log(i); // 0, 1, 3, 4 } // Skip even numbers for (let i = 0; i < 10; i++) { if (i % 2 === 0) continue; console.log(i); // 1, 3, 5, 7, 9 }

Labeled Statements

javascript
// Labels allow breaking/continuing outer loops outer: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (i === 1 && j === 1) { break outer; // Breaks outer loop } console.log(`${i}, ${j}`); } } // 0, 0 // 0, 1 // 0, 2 // 1, 0 // Continue with label outer: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (j === 1) { continue outer; // Continues outer loop } console.log(`${i}, ${j}`); } } // 0, 0 // 1, 0 // 2, 0

Modern Iteration Methods

Often, array methods are cleaner than loops.

forEach

javascript
const numbers = [1, 2, 3, 4, 5]; numbers.forEach((num, index) => { console.log(`${index}: ${num}`); }); // Cannot break out of forEach // Use traditional loop or some/every if you need early exit

map, filter, reduce

javascript
const numbers = [1, 2, 3, 4, 5]; // Transform each element const doubled = numbers.map(n => n * 2); console.log(doubled); // [2, 4, 6, 8, 10] // Filter elements const evens = numbers.filter(n => n % 2 === 0); console.log(evens); // [2, 4] // Reduce to single value const sum = numbers.reduce((acc, n) => acc + n, 0); console.log(sum); // 15 // Chaining const result = numbers .filter(n => n % 2 !== 0) // [1, 3, 5] .map(n => n * 2) // [2, 6, 10] .reduce((a, b) => a + b); // 18

some and every

javascript
const numbers = [1, 2, 3, 4, 5]; // Check if any element matches (exits early) const hasEven = numbers.some(n => n % 2 === 0); console.log(hasEven); // true // Check if all elements match (exits early) const allPositive = numbers.every(n => n > 0); console.log(allPositive); // true // Useful for validation const users = [ { name: 'Alice', active: true }, { name: 'Bob', active: true }, { name: 'Charlie', active: false } ]; const allActive = users.every(user => user.active); const anyActive = users.some(user => user.active);

find and findIndex

javascript
const users = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]; // Find first matching element const user = users.find(u => u.id === 2); console.log(user); // { id: 2, name: 'Bob' } // Find index of first match const index = users.findIndex(u => u.id === 2); console.log(index); // 1 // Returns undefined/-1 if not found const notFound = users.find(u => u.id === 999); console.log(notFound); // undefined

Exception Handling

try...catch

javascript
try { // Code that might throw const result = riskyOperation(); console.log(result); } catch (error) { // Handle the error console.error('Something went wrong:', error.message); } // Catch specific error types try { JSON.parse('invalid json'); } catch (error) { if (error instanceof SyntaxError) { console.log('Invalid JSON'); } else { throw error; // Re-throw unexpected errors } }

finally

javascript
// finally always runs function readFile() { const file = openFile(); try { return processFile(file); } catch (error) { console.error('Error processing file'); return null; } finally { closeFile(file); // Always runs, even after return } } // Cleanup pattern let connection; try { connection = database.connect(); connection.query('SELECT * FROM users'); } catch (error) { console.error('Database error'); } finally { if (connection) { connection.close(); } }

throw Statement

javascript
// Throw built-in errors function divide(a, b) { if (b === 0) { throw new Error('Division by zero'); } return a / b; } // Throw custom errors class ValidationError extends Error { constructor(message) { super(message); this.name = 'ValidationError'; } } function validateAge(age) { if (typeof age !== 'number') { throw new ValidationError('Age must be a number'); } if (age < 0 || age > 150) { throw new ValidationError('Age must be between 0 and 150'); } return true; } try { validateAge(-5); } catch (error) { if (error instanceof ValidationError) { console.log('Validation failed:', error.message); } else { throw error; } }

Summary

Conditional statements:
  • if, else if, else for branching logic
  • switch for multiple case comparisons
  • Ternary operator for simple conditional expressions
Loops:
  • for when you know the number of iterations
  • for...of for iterating values of iterables
  • for...in for object keys (with caution)
  • while when condition determines iterations
  • do...while when you need at least one iteration
Loop control:
  • break to exit loops early
  • continue to skip iterations
  • Labels for nested loop control
Modern alternatives:
  • Array methods (forEach, map, filter, reduce) often replace loops
  • some, every, find, findIndex for searching

Questions to Think About

  1. When should you use switch vs if...else?
Use switch when comparing one value against many specific cases. Use if...else for complex conditions, ranges, or when cases aren't discrete values. Object lookup is often cleaner than both for simple mappings.
  1. Why is for...of preferred over for...in for arrays?
for...in iterates over all enumerable properties, including inherited ones and non-index properties. for...of iterates over values and works with all iterables, not just arrays.
  1. When should you use array methods instead of loops?
Array methods like map, filter, and reduce are preferred when you're transforming data and want to write declarative, functional code. Traditional loops are better when you need break/continue or performance is critical.
  1. How does the finally block work with return?
finally always executes, even if try or catch contain a return statement. The return value is preserved, but finally runs before the function actually returns.
  1. What's the difference between break and continue?
break exits the loop entirely. continue skips the rest of the current iteration and moves to the next one.

Next: Part 5 - Functions Fundamentals, where we explore function declarations, expressions, arrow functions, and scope.
All Blogs
Tags:javascriptcontrol-flowconditionalsloopsswitch