Conditional Statements
Conditional statements allow your code to make decisions. They execute different code blocks based on whether a condition is true or false.
if Statement
The if statement executes a block of code only if a condition is true.
const age = 18;
// Basic if statement
if (age >= 18) {
console.log("You are an adult");
}
// The condition can be any expression that evaluates to truthy/falsy
const isLoggedIn = true;
if (isLoggedIn) {
console.log("Welcome back!");
}
// Checking for existence
const username = "john_doe";
if (username) {
console.log(`Hello, ${username}`);
}
if...else Statement
Use else to specify code that runs when the condition is false.
const temperature = 15;
if (temperature > 25) {
console.log("It's hot outside!");
} else {
console.log("It's not too hot.");
}
// Checking user authentication
const user = null;
if (user) {
console.log(`Welcome, ${user.name}`);
} else {
console.log("Please log in");
}
else if - Multiple Conditions
Chain multiple conditions using else if.
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");
}
// Time-based greeting
const hour = new Date().getHours();
if (hour < 12) {
console.log("Good morning!");
} else if (hour < 17) {
console.log("Good afternoon!");
} else if (hour < 21) {
console.log("Good evening!");
} else {
console.log("Good night!");
}
Order Matters
Conditions are checked in order, and only the first matching block runs. Put more specific conditions before general ones.
Ternary Operator
A shorthand for simple if-else statements. Syntax: condition ? valueIfTrue : valueIfFalse
const age = 20;
// Instead of:
// if (age >= 18) {
// status = "adult";
// } else {
// status = "minor";
// }
// Use ternary:
const status = age >= 18 ? "adult" : "minor";
console.log(status); // "adult"
// Inline in template literals
console.log(`You are ${age >= 18 ? "an adult" : "a minor"}`);
// Nested ternary (use sparingly, can be hard to read)
const score = 85;
const grade = score >= 90 ? "A"
: score >= 80 ? "B"
: score >= 70 ? "C"
: "F";
// Great for conditional values
const greeting = user ? `Hello, ${user.name}` : "Hello, guest";
const discount = isPremium ? 0.2 : 0;
Advanced Ternary Patterns
The ternary operator is powerful for inline conditionals, but use it wisely to maintain readability.
// Pattern 1: Default values with ternary
const name = inputName ? inputName : "Anonymous";
// Better with nullish coalescing:
const name = inputName ?? "Anonymous";
// Pattern 2: Conditional function calls
const result = isAsync ? await fetchData() : getData();
// Pattern 3: Conditional object properties
const config = {
mode: isDev ? "development" : "production",
debug: isDev ? true : false,
apiUrl: isDev
? "http://localhost:3000"
: "https://api.example.com"
};
// Pattern 4: Conditional array methods
const items = shouldSort
? data.sort((a, b) => a.name.localeCompare(b.name))
: data;
// Pattern 5: Conditional class names (common in React)
const className = `button ${isActive ? "active" : ""} ${isDisabled ? "disabled" : ""}`.trim();
// Pattern 6: Conditional JSX/template rendering
const message = count === 0
? "No items"
: count === 1
? "1 item"
: `${count} items`;
// ❌ Avoid: Over-nested ternaries (hard to read)
const result = a ? b ? c ? "abc" : "ab" : "a" : "none";
// ✅ Better: Use if-else or switch for complex logic
function getResult(a, b, c) {
if (!a) return "none";
if (!b) return "a";
if (!c) return "ab";
return "abc";
}
When to Use Ternary
Use ternary for simple, inline conditionals. If you're nesting more than 2 levels or the logic is complex, switch to if-else for better readability.
switch Statement
Use switch when comparing one value against many possible matches. Cleaner than many else-if chains.
const day = "Monday";
switch (day) {
case "Monday":
console.log("Start of the 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");
}
// Switch with expressions
const fruit = "apple";
let color;
switch (fruit) {
case "banana":
color = "yellow";
break;
case "apple":
color = "red";
break;
case "grape":
color = "purple";
break;
default:
color = "unknown";
}
console.log(`A ${fruit} is ${color}`); // "A apple is red"
Don't Forget break!
Without break, execution "falls through" to the next case. This is sometimes useful, but usually a bug if unintentional.
switch vs if-else: When to Use Which
Both constructs can handle multiple conditions, but they have different strengths:
// ✅ Use switch when:
// - Comparing ONE variable against MULTIPLE exact values
// - Cases are discrete values (not ranges)
// - You need fall-through behavior
switch (action) {
case "create":
case "add": // Fall-through for similar actions
return handleCreate();
case "update":
case "edit":
return handleUpdate();
case "delete":
case "remove":
return handleDelete();
default:
return handleUnknown();
}
// ✅ Use if-else when:
// - Comparing ranges or complex conditions
// - Conditions involve multiple variables
// - Using operators like >, <, >=, <=
if (age < 13) {
return "child";
} else if (age < 20) {
return "teenager";
} else if (age < 65) {
return "adult";
} else {
return "senior";
}
// ❌ switch can't easily do range checks:
// switch (age) { case < 13: ... } // INVALID!
// ✅ Modern alternative: Object lookup (often fastest)
const actions = {
create: handleCreate,
add: handleCreate,
update: handleUpdate,
edit: handleUpdate,
delete: handleDelete,
remove: handleDelete
};
const handler = actions[action] || handleUnknown;
handler();
Performance Note
For most cases, performance difference is negligible. Object lookups are O(1) and often fastest for string/number keys. Choose based on readability first, then optimize if profiling shows a bottleneck.
Loops
Loops repeat code multiple times. They're essential for processing lists, waiting for conditions, and automating repetitive tasks.
for Loop
The classic loop with initialization, condition, and increment in one line.
// Basic for loop
// for (initialization; condition; increment) { code }
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
// Counting backwards
for (let i = 5; i > 0; i--) {
console.log(i); // 5, 4, 3, 2, 1
}
// Stepping by 2
for (let i = 0; i <= 10; i += 2) {
console.log(i); // 0, 2, 4, 6, 8, 10
}
// Looping through an array
const fruits = ["apple", "banana", "cherry"];
for (let i = 0; i < fruits.length; i++) {
console.log(`${i}: ${fruits[i]}`);
}
// Output:
// 0: apple
// 1: banana
// 2: cherry
// Nested loops (for grids, matrices)
for (let row = 1; row <= 3; row++) {
for (let col = 1; col <= 3; col++) {
console.log(`Row ${row}, Col ${col}`);
}
}
while Loop
Repeats as long as a condition is true. Best when you don't know how many iterations you need.
// Basic while loop
let count = 0;
while (count < 5) {
console.log(count);
count++;
}
// Output: 0, 1, 2, 3, 4
// Waiting for a condition
let number = 1;
while (number <= 1000) {
number *= 2;
}
console.log(number); // 1024 (first power of 2 over 1000)
// Processing until empty
const tasks = ["task1", "task2", "task3"];
while (tasks.length > 0) {
const task = tasks.pop();
console.log(`Processing: ${task}`);
}
// Output:
// Processing: task3
// Processing: task2
// Processing: task1
Beware Infinite Loops!
Always ensure the condition will eventually become false. An infinite loop will freeze your browser or crash your program.
do...while Loop
Like while, but the code runs at least once before checking the condition.
// Runs at least once
let num = 10;
do {
console.log(num); // 10 (runs once even though condition is false)
num++;
} while (num < 5);
// Useful for input validation (conceptually)
let userInput;
do {
// In real code, this would prompt the user
userInput = Math.random() > 0.3 ? "valid" : "invalid";
console.log(`Got: ${userInput}`);
} while (userInput !== "valid");
for...of Loop (ES6)
The modern way to iterate over arrays and other iterable objects. Cleaner than traditional for loops.
// Iterate over array values
const colors = ["red", "green", "blue"];
for (const color of colors) {
console.log(color);
}
// Output: red, green, blue
// Iterate over string characters
const word = "Hello";
for (const char of word) {
console.log(char);
}
// Output: H, e, l, l, o
// With array entries (get index too)
for (const [index, color] of colors.entries()) {
console.log(`${index}: ${color}`);
}
// Output:
// 0: red
// 1: green
// 2: blue
for...in Loop
Iterates over object property names (keys). Not recommended for arrays.
// Iterate over object keys
const user = {
name: "John",
age: 30,
city: "New York"
};
for (const key in user) {
console.log(`${key}: ${user[key]}`);
}
// Output:
// name: John
// age: 30
// city: New York
// Better alternatives for objects:
Object.keys(user).forEach(key => console.log(key));
Object.values(user).forEach(value => console.log(value));
Object.entries(user).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
break and continue
// break - exit the loop entirely
for (let i = 0; i < 10; i++) {
if (i === 5) {
break; // Stop when i reaches 5
}
console.log(i);
}
// Output: 0, 1, 2, 3, 4
// continue - skip to next iteration
for (let i = 0; i < 5; i++) {
if (i === 2) {
continue; // Skip when i is 2
}
console.log(i);
}
// Output: 0, 1, 3, 4
// Finding first match
const numbers = [3, 7, 2, 9, 5];
let firstEven;
for (const num of numbers) {
if (num % 2 === 0) {
firstEven = num;
break;
}
}
console.log(firstEven); // 2
// Skipping invalid items
const data = [1, null, 3, undefined, 5];
for (const item of data) {
if (item == null) continue;
console.log(item * 2);
}
// Output: 2, 6, 10
Labeled Statements (Nested Loop Control)
// Labels let you break/continue outer loops
outerLoop: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
break outerLoop; // Breaks BOTH loops
}
console.log(`i=${i}, j=${j}`);
}
}
// Output:
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
// (stops at i=1, j=1)
// Without label, only inner loop breaks
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (j === 1) {
break; // Only breaks inner loop
}
console.log(`i=${i}, j=${j}`);
}
}
Loop Optimization Tips
For most code, loop performance isn't a concern. But when processing large datasets, these optimizations can make a significant difference:
Cache Array Length
const largeArray = new Array(1000000).fill(0);
// ❌ Recalculates length each iteration
for (let i = 0; i < largeArray.length; i++) {
// process
}
// ✅ Cache length (minor but measurable improvement)
for (let i = 0, len = largeArray.length; i < len; i++) {
// process
}
// ✅ Or use for...of (handles it internally)
for (const item of largeArray) {
// process
}
Avoid Work Inside Loops
// ❌ Repeatedly accessing DOM
for (let i = 0; i < items.length; i++) {
document.getElementById("container").appendChild(
createItem(items[i])
);
}
// ✅ Cache DOM reference outside loop
const container = document.getElementById("container");
for (let i = 0; i < items.length; i++) {
container.appendChild(createItem(items[i]));
}
// ✅ Even better: Build fragment, insert once
const fragment = document.createDocumentFragment();
for (const item of items) {
fragment.appendChild(createItem(item));
}
container.appendChild(fragment);
// ❌ Unnecessary calculations inside loop
for (let i = 0; i < arr.length; i++) {
const factor = Math.sqrt(baseValue) * coefficient;
result[i] = arr[i] * factor;
}
// ✅ Calculate constants outside
const factor = Math.sqrt(baseValue) * coefficient;
for (let i = 0; i < arr.length; i++) {
result[i] = arr[i] * factor;
}
Choose the Right Loop
const arr = [1, 2, 3, 4, 5];
// Performance ranking (generally):
// 1. Traditional for loop - fastest
// 2. for...of - very close, more readable
// 3. forEach - slightly slower, functional style
// 4. for...in - slowest, not for arrays!
// ✅ Use traditional for when you need index manipulation
for (let i = arr.length - 1; i >= 0; i--) {
// Reverse iteration
}
// ✅ Use for...of for clean iteration
for (const item of arr) {
// Most readable for simple iteration
}
// ✅ Use forEach for side effects
arr.forEach((item, index) => {
console.log(`${index}: ${item}`);
});
// ✅ Use map/filter/reduce for transformations
const doubled = arr.map(x => x * 2);
const evens = arr.filter(x => x % 2 === 0);
const sum = arr.reduce((acc, x) => acc + x, 0);
// ❌ Don't use for...in with arrays
for (const i in arr) {
// i is a string, not a number!
// Also iterates inherited properties
}
Early Exit Strategies
// ✅ Use break to exit early when found
function findUser(users, id) {
for (const user of users) {
if (user.id === id) {
return user; // Exit immediately
}
}
return null;
}
// ✅ Use array methods with early exit
const found = users.find(user => user.id === id);
const exists = users.some(user => user.id === id);
// ✅ For validation, exit on first failure
function validateAll(items) {
for (const item of items) {
if (!isValid(item)) {
return false; // Don't check rest
}
}
return true;
}
// Same with every()
const allValid = items.every(isValid);
The Golden Rule
Write readable code first. Only optimize loops when profiling shows they're a bottleneck. Premature optimization is the root of all evil! 99% of the time, for...of or array methods are the right choice.
Summary
You've learned how to control the flow of your JavaScript programs:
- if/else: Make decisions based on conditions
- Ternary operator: Concise conditional expressions; avoid deep nesting
- switch: Compare one value against many exact matches
- switch vs if-else: Use switch for exact values, if-else for ranges/complex conditions
- for loop: Repeat a known number of times with full control
- while loop: Repeat while a condition is true
- do...while: Run at least once, then check condition
- for...of: Modern way to iterate over arrays (recommended)
- for...in: Iterate over object keys (not for arrays)
- break/continue: Exit loops or skip iterations
- Labeled statements: Control nested loops with precision
- Loop optimization: Cache length, avoid work inside loops, exit early
Next Steps
With conditionals and loops, you can create dynamic programs. Next, learn about functions to organize your code into reusable building blocks!