04. Control Flow
Conditions are evaluated as truthy/falsy. When you have three or more branches, consider `switch` or a data-driven object lookup instead of long `if/else` chains.
What you'll learn
- 1Branch on conditions with `if / else if / else`.
- 2Understand `switch` and its `break`-fallthrough trap.
- 3Distinguish `for`, `while`, `for...of`, and `for...in`.
- 4Control loop flow with `break` and `continue`.
- 5Write simple conditional expressions with the ternary operator.
Overview
Conditions are evaluated as truthy/falsy. When you have three or more branches, consider `switch` or a data-driven object lookup instead of long `if/else` chains.
Core Concepts
1. Conditional branching: if / else
Conditions are evaluated as truthy/falsy. When you have three or more branches, consider `switch` or a data-driven object lookup instead of long `if/else` chains.
if (score >= 90) grade = "A";
else if (score >= 80) grade = "B";
else grade = "C";2. switch
`switch` branches on exact equality. Forgetting `break` at the end of a `case` falls through to the next case. If you mean to fall through, leave an explicit comment.
switch (day) {
case "Sat":
case "Sun":
console.log("weekend");
break;
default:
console.log("weekday");
}3. Loops
- `for (let i = 0; i < n; i++)` β when you need the index.
- `while (cond)` β when only the exit condition matters.
- `for...of` β iterate values of arrays, strings, or any iterable.
- `for...in` β iterate object keys (avoid for arrays).
for (const ch of "JS") console.log(ch);
for (const key in { a: 1, b: 2 }) console.log(key);4. break / continue / ternary
`break` exits a loop immediately; `continue` skips the current iteration. The ternary operator is concise when you just need to pick a value.
const label = age >= 18 ? "adult" : "minor";Examples
| File | What it covers |
|---|---|
| `01_if_else.js` | Score-to-grade branching plus a ternary |
| `02_switch.js` | switch fallthrough and grouped cases |
| `03_for_loops.js` | for vs while vs for...of vs for...in |
| `04_break_continue.js` | Skip even numbers and exit early |
src/01_if_else.js
/** Convert a score to a letter grade. */
function grade(score) {
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
if (score >= 60) return "D";
return "F";
}
for (const s of [95, 82, 71, 60, 45]) {
const pass = s >= 60 ? "pass" : "fail";
console.log(`${s} β ${grade(s)} (${pass})`);
}
src/02_switch.js
/** Demonstrate grouped cases and fallthrough in switch. */
function describe(day) {
switch (day) {
case "Mon":
case "Tue":
case "Wed":
case "Thu":
case "Fri":
return "weekday";
case "Sat":
case "Sun":
return "weekend";
default:
return "unknown";
}
}
for (const d of ["Mon", "Sat", "Xyz"]) {
console.log(d, "β", describe(d));
}
src/03_for_loops.js
/** Compare the four loop styles. */
const arr = ["a", "b", "c"];
// 1) Classic for
for (let i = 0; i < arr.length; i += 1) {
console.log("for", i, arr[i]);
}
// 2) while
let i = 0;
while (i < arr.length) {
console.log("while", arr[i]);
i += 1;
}
// 3) for...of (values β recommended for arrays/iterables)
for (const v of arr) console.log("for...of", v);
// 4) for...in (keys β recommended for objects)
const obj = { x: 1, y: 2 };
for (const key in obj) console.log("for...in", key, "=", obj[key]);
src/04_break_continue.js
/** Skip evens with continue, bail out early with break. */
for (let i = 1; i <= 10; i += 1) {
if (i % 2 === 0) continue;
if (i > 7) break;
console.log("odd:", i);
}
// Guard-clause pattern
function greet(name) {
if (!name) return "name is missing";
return `Hello, ${name}!`;
}
console.log(greet(""));
console.log(greet("Ada"));
Common Mistakes
- Forgetting `break` at the end of a `case` and falling through unintentionally.
- Mixing `for (var i ...)` with async callbacks so the shared `i` causes bugs β use `let`.
- Iterating an array with `for...in`, getting string indices, and possibly out-of-order traversal.
- Writing an infinite loop and forgetting to update the exit condition.
- Nesting ternaries so deeply that readability collapses.
FAQ
Q1. Should I use `for` or `forEach`?
If you need `break`, use `for`/`for...of`. For a plain iteration, `forEach` is fine too.
Q2. Should I always avoid `switch`?
When the branches are clearly value-based, `switch` reads well. As branching gets complex, switch to an object lookup.
Q3. Doesn't `continue` make code hard to follow?
When used as a guard clause to flatten nesting, it usually improves readability.
Practice
- `homework_01.js` β FizzBuzz (1 to 30: multiples of 3 β Fizz, of 5 β Buzz, of both β FizzBuzz).
- `homework_02.js` β Take an array of scores and bucket them into a grade-count object.
homework/README.md
## homework_01.js β FizzBuzz
- Print numbers 1 to 30, but:
- Multiples of 3 β "Fizz"
- Multiples of 5 β "Buzz"
- Multiples of both β "FizzBuzz"
- Otherwise β the number itself.
## homework_02.js
- Given `[92, 78, 65, 88, 55, 100]`, output a count per grade AβF.
- Example: `{ A: 2, B: 1, C: 1, D: 1, F: 1 }`
homework/answer/homework_01.js
/** FizzBuzz 1..30 */
for (let i = 1; i <= 30; i += 1) {
if (i % 15 === 0) console.log("FizzBuzz");
else if (i % 3 === 0) console.log("Fizz");
else if (i % 5 === 0) console.log("Buzz");
else console.log(i);
}
homework/answer/homework_02.js
/** Bucket scores by letter grade. */
function gradeOf(score) {
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
if (score >= 60) return "D";
return "F";
}
const scores = [92, 78, 65, 88, 55, 100];
const summary = { A: 0, B: 0, C: 0, D: 0, F: 0 };
for (const s of scores) {
summary[gradeOf(s)] += 1;
}
console.log(summary);
Next Lecture
[05_Functions_Basics](../05_ν¨μ_κΈ°μ΄/) β Bundle code into reusable units.
All lecture materials and example code are openly available on GitHub.
View on GitHub β