Skip to main content

Module 3: Control Flow & Conditional Statements

This module teaches you how to make decisions in your code using conditional statements and how to control the flow of execution.


1. Conditional Statements

1.1 if Statement

const age = 18;

if (age >= 18) {
console.log('You are an adult');
}

1.2 if-else Statement

const age = 16;

if (age >= 18) {
console.log('You are an adult');
} else {
console.log('You are a minor');
}

1.3 if-else if-else Statement

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');
}

1.4 Nested if Statements

const age = 25;
const hasLicense = true;

if (age >= 18) {
if (hasLicense) {
console.log('You can drive');
} else {
console.log('You need a license');
}
} else {
console.log('You are too young to drive');
}
Keep It Simple

Avoid deep nesting. Consider refactoring into separate functions or using early returns.


2. Ternary Operator

// Syntax: condition ? valueIfTrue : valueIfFalse
const age = 20;
const status = age >= 18 ? 'Adult' : 'Minor';

// Multiple ternaries
const grade = score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : 'F';

// With function calls
const message = isLoggedIn ? getUserData() : showLogin();
Readability

Nested ternaries can be hard to read. Use if-else for complex conditions.


3. Switch Statement

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('Almost weekend!');
break;
case 'Saturday':
case 'Sunday':
console.log('Weekend!');
break;
default:
console.log('Invalid day');
}

Switch with Expressions

const getStatus = (code) => {
switch (code) {
case 200:
return 'OK';
case 404:
return 'Not Found';
case 500:
return 'Server Error';
default:
return 'Unknown Status';
}
};
When to Use Switch

Use switch when you have multiple discrete values to check against a single variable.


4. Truthy and Falsy Values

Falsy Values (6 total)

false       // Boolean false
0 // Number zero
'' // Empty string
null // Null
undefined // Undefined
NaN // Not a Number

// All evaluate to false in conditions
if (0) { /* won't execute */ }
if ('') { /* won't execute */ }

Truthy Values

// Everything else is truthy
true
1, -1, 100
'hello', '0', 'false'
[] // Empty array
{} // Empty object
function(){}// Function

Practical Usage

// Default values
const name = userName || 'Guest';

// Validation
if (!email) {
console.log('Email is required');
}

// Guard clauses
function processUser(user) {
if (!user) return;
// Process user
}

5. Logical Operators in Conditions

5.1 AND (&&)

const age = 25;
const hasLicense = true;

if (age >= 18 && hasLicense) {
console.log('Can drive');
}

// Short-circuit evaluation
const result = user && user.name; // Returns user.name if user exists

5.2 OR (||)

const role = 'admin';

if (role === 'admin' || role === 'moderator') {
console.log('Has elevated privileges');
}

// Default values
const port = process.env.PORT || 3000;

5.3 NOT (!)

const isLoggedOut = !isLoggedIn;

if (!isActive) {
console.log('Account is inactive');
}

5.4 Complex Conditions

if ((age >= 18 && hasLicense) || hasSpecialPermit) {
console.log('Eligible to drive');
}

// Readability improvement
const isEligibleToDrive = (age >= 18 && hasLicense) || hasSpecialPermit;
if (isEligibleToDrive) {
console.log('Eligible to drive');
}

6. Guard Clauses (Early Returns)

Bad: Deep Nesting

function processOrder(order) {
if (order) {
if (order.items.length > 0) {
if (order.total > 0) {
// Process order
return 'Order processed';
} else {
return 'Invalid total';
}
} else {
return 'No items';
}
} else {
return 'No order';
}
}

Good: Guard Clauses

function processOrder(order) {
if (!order) return 'No order';
if (order.items.length === 0) return 'No items';
if (order.total <= 0) return 'Invalid total';

// Process order
return 'Order processed';
}
Best Practice

Use early returns to handle error cases first, keeping the main logic at the lowest indentation level.


7. Nullish Coalescing (??) vs OR (||)

// OR operator (||)
const port1 = 0 || 8080; // 8080 (0 is falsy)
const name1 = '' || 'Guest'; // 'Guest' (empty string is falsy)

// Nullish coalescing (??)
const port2 = 0 ?? 8080; // 0 (0 is not nullish)
const name2 = '' ?? 'Guest'; // '' (empty string is not nullish)

// Only null and undefined are nullish
const value1 = null ?? 'default'; // 'default'
const value2 = undefined ?? 'default'; // 'default'
Use Case

Use ?? when you want to provide defaults only for null/undefined, not for all falsy values.


8. Optional Chaining (?.)

const user = {
name: 'John',
address: {
city: 'New York'
}
};

// Without optional chaining
const zip = user && user.address && user.address.zip;

// With optional chaining
const zip = user?.address?.zip; // undefined (no error)

// With arrays
const firstItem = items?.[0];

// With functions
const result = obj.method?.();

9. Pattern Matching Alternatives

Object Lookup Pattern

// Instead of switch
const statusMessages = {
200: 'OK',
404: 'Not Found',
500: 'Server Error'
};

const message = statusMessages[code] || 'Unknown';

Function Map Pattern

const operations = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b,
divide: (a, b) => a / b
};

const result = operations[operator]?.(x, y);

10. Best Practices

10.1 Avoid Magic Numbers

// Bad
if (status === 1) {
// What does 1 mean?
}

// Good
const STATUS_ACTIVE = 1;
const STATUS_INACTIVE = 0;

if (status === STATUS_ACTIVE) {
// Clear intent
}

10.2 Positive Conditionals

// Bad
if (!isNotValid) {}

// Good
if (isValid) {}

10.3 Explicit Comparisons

// Less clear
if (items.length) {}

// More clear
if (items.length > 0) {}

10.4 Use Meaningful Variable Names

// Bad
if (x > 18 && y) {}

// Good
const isAdult = age > 18;
const hasPermission = user.role === 'admin';
if (isAdult && hasPermission) {}

Summary

In this module, you learned:

  • ✅ if, if-else, and if-else if statements
  • ✅ Ternary operator for simple conditions
  • ✅ Switch statements for multiple cases
  • ✅ Truthy and falsy values
  • ✅ Logical operators (&&, ||, !)
  • ✅ Guard clauses and early returns
  • ✅ Modern features: ??, ?.
  • ✅ Best practices for readable conditions
Next Steps

In Module 4, you'll learn about Loops and Iteration to repeat code execution efficiently.


Practice Exercises

  1. Write a function that returns the day of week name from a number (1-7)
  2. Create a grade calculator using if-else if
  3. Implement age verification with nested conditions
  4. Refactor nested if statements into guard clauses
  5. Create a simple calculator using switch statement
  6. Write validation logic using optional chaining
  7. Compare behavior of || vs ?? operators
  8. Build a user permission checker with complex conditions

Additional Resources