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