Control Flow
Control flow is how you make your programs smart. Instead of just running code line by line, you can make decisions (if/else) and repeat actions (loops). This is where your code becomes truly powerful!
What You'll Learn
- How to use if/else statements to make decisions
- Different types of loops for repeating code
- The ternary operator for simple conditions
- When to use break and continue
If Statements
If statements let your code make decisions:
let temperature = 75;
if (temperature > 80) {
console.log("It's hot outside!");
}
if (temperature <= 80) {
console.log("The weather is nice!");
}
If/Else Statements
Use else to handle the alternative case:
let age = 20;
if (age >= 18) {
console.log("You are an adult");
} else {
console.log("You are a minor");
}
// Another example
let 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");
}
Predict
Trace this by hand before running it. Note that BOTH conditions are true for n = 12. What does it log?
let n = 12;
if (n > 5) {
console.log("big");
} else if (n > 10) {
console.log("bigger");
} else {
console.log("small");
}Only the first matching branch runs. Because n > 5 is true, the chain logs "big" and skips every later else if — even though n > 10 is also true for 12. This is why the order of an if/else-if chain matters: put the more specific (narrower) conditions first, or the broad one will always win.
Comparison Operators
These operators are used in conditions:
let x = 10;
let y = 20;
console.log("x === y:", x === y); // Equal to (strict)
console.log("x !== y:", x !== y); // Not equal to
console.log("x < y:", x < y); // Less than
console.log("x > y:", x > y); // Greater than
console.log("x <= y:", x <= y); // Less than or equal
console.log("x >= y:", x >= y); // Greater than or equal
Recall
Without scrolling up: back in 02-variables-and-types you saw that a comparison like 5 > 3 produces a value. What TYPE of value does an expression like x < y evaluate to, and why does that matter for an if condition?
Logical Operators
Combine multiple conditions:
let age = 25;
let hasLicense = true;
// AND operator (&&) - both must be true
if (age >= 18 && hasLicense) {
console.log("You can drive!");
}
// OR operator (||) - at least one must be true
let isWeekend = true;
let isHoliday = false;
if (isWeekend || isHoliday) {
console.log("You can relax!");
}
// NOT operator (!) - reverses the condition
let isSleeping = false;
if (!isSleeping) {
console.log("You are awake!");
}
Ternary Operator
A shorthand for simple if/else statements:
// Syntax: condition ? valueIfTrue : valueIfFalse
let age = 20;
let status = age >= 18 ? "adult" : "minor";
console.log("Status:", status);
// Another example
let score = 85;
let result = score >= 60 ? "Pass" : "Fail";
console.log("Result:", result);
// You can use it directly
console.log("Can vote:", age >= 18 ? "Yes" : "No");
For Loops
Repeat code a specific number of times:
// Count from 1 to 5
for (let i = 1; i <= 5; i++) {
console.log("Count:", i);
}
// Countdown from 5 to 1
for (let i = 5; i >= 1; i--) {
console.log("Countdown:", i);
}
// Count by 2s
for (let i = 0; i <= 10; i += 2) {
console.log("Even number:", i);
}
Debug
This loop should add up 1 + 2 + 3 + 4 + 5 and log 'Sum: 15'. Instead it crashes on the very first iteration with a TypeError before printing anything. Predict what goes wrong, then fix it so it logs 'Sum: 15'.
let sum = 0;
for (const i = 1; i <= 5; i++) {
sum += i;
}
console.log("Sum:", sum);Expected output: Sum: 15
While Loops
Repeat code while a condition is true:
// Count to 5 with while loop
let count = 1;
while (count <= 5) {
console.log("While count:", count);
count++;
}
// Find first power of 2 greater than 100
let power = 1;
while (power <= 100) {
power = power * 2;
}
console.log("First power of 2 > 100:", power);
Do-While Loops
Like while loops, but always run at least once:
let num = 1;
do {
console.log("Number:", num);
num++;
} while (num <= 3);
// This runs once even though condition is false
let x = 10;
do {
console.log("This prints once, x =", x);
} while (x < 5);
Break and Continue
Control loop execution:
// Break - exit the loop early
console.log("Using break:");
for (let i = 1; i <= 10; i++) {
if (i === 5) {
console.log("Breaking at", i);
break;
}
console.log(i);
}
// Continue - skip to next iteration
console.log("\nUsing continue:");
for (let i = 1; i <= 5; i++) {
if (i === 3) {
console.log("Skipping", i);
continue;
}
console.log(i);
}
Practical Examples
Let's combine what we've learned:
// Find all even numbers from 1 to 10
console.log("Even numbers from 1 to 10:");
for (let i = 1; i <= 10; i++) {
if (i % 2 === 0) {
console.log(i);
}
}
// FizzBuzz (classic programming challenge)
console.log("\nFizzBuzz:");
for (let i = 1; i <= 15; i++) {
if (i % 3 === 0 && i % 5 === 0) {
console.log("FizzBuzz");
} else if (i % 3 === 0) {
console.log("Fizz");
} else if (i % 5 === 0) {
console.log("Buzz");
} else {
console.log(i);
}
}
// Calculate factorial
let n = 5;
let factorial = 1;
for (let i = 1; i <= n; i++) {
factorial *= i;
}
console.log("\nFactorial of", n, "is", factorial);
Try It Yourself
Reading about conditions and loops is not the same as building with them. This is a build task: a small program that reports its own pass/fail. You are given three empty functions to finish, each one a small decision or counting problem. Run it and it fails immediately, telling you which function is still missing. Implement each one until every check passes and it prints All checks passed.
The three functions reuse exactly what this lesson taught: an if/else if chain that returns the first matching result, the modulo operator to test divisibility, and a counting for loop with a running total. The starter already has the data, the stubs, and the checks — you write only the logic inside each function. Nothing above spells out all three answers, so you will have to assemble them yourself.
Build
Finish the build. Three functions are stubbed out and the checks below them fail until each one returns the right value. Run it as-is to see which check fails first, decide what that function is missing, then implement the three functions until it prints 'All checks passed.' The checks run top to bottom, so the first failure you see is TODO 1 — implement it first, then work down.
const assert = require('assert');
// The data: fixed inputs to check against. Do NOT change these values.
const limit = 15;
const childAge = 8;
const adultAge = 40;
const seniorAge = 70;
// TODO 1: return a word for one FizzBuzz number.
// Divisible by 3 AND 5 -> "FizzBuzz"; by 3 only -> "Fizz";
// by 5 only -> "Buzz"; otherwise the number as a string.
// fizzbuzzWord(15) -> "FizzBuzz", fizzbuzzWord(9) -> "Fizz", fizzbuzzWord(7) -> "7"
function fizzbuzzWord(n) {
// your code here
}
// TODO 2: count how many integers from 1 to limit are divisible by factor.
// countDivisibleBy(15, 3) -> 5
function countDivisibleBy(limit, factor) {
// your code here
}
// TODO 3: return a ticket fare for an age.
// Under 13 -> 5; 65 or older -> 8; everyone else -> 12.
// fareFor(8) -> 5, fareFor(40) -> 12, fareFor(70) -> 8
function fareFor(age) {
// your code here
}
// --- Build checks: these must all pass. Do not edit below this line. ---
assert.strictEqual(
fizzbuzzWord(15),
"FizzBuzz",
"fizzbuzzWord(n) should return 'FizzBuzz' when n is divisible by both 3 and 5",
);
assert.strictEqual(
fizzbuzzWord(9),
"Fizz",
"fizzbuzzWord(n) should return 'Fizz' when n is divisible by 3 only",
);
assert.strictEqual(
fizzbuzzWord(10),
"Buzz",
"fizzbuzzWord(n) should return 'Buzz' when n is divisible by 5 only",
);
assert.strictEqual(
fizzbuzzWord(7),
"7",
"fizzbuzzWord(n) should return the number as a string when it is divisible by neither 3 nor 5",
);
assert.strictEqual(
countDivisibleBy(limit, 3),
5,
"countDivisibleBy(limit, factor) should count how many integers from 1 to limit divide evenly by factor",
);
assert.strictEqual(
fareFor(childAge),
5,
"fareFor(age) should charge 5 for anyone under 13",
);
assert.strictEqual(
fareFor(adultAge),
12,
"fareFor(age) should charge 12 for a standard adult",
);
assert.strictEqual(
fareFor(seniorAge),
8,
"fareFor(age) should charge 8 for anyone 65 or older",
);
console.log("All checks passed.");
console.log("fizzbuzzWord(15):", fizzbuzzWord(15));
console.log("countDivisibleBy(15, 3):", countDivisibleBy(limit, 3));
console.log("fareFor(70):", fareFor(seniorAge));Expected output: All checks passed.
fizzbuzzWord(15): FizzBuzz
countDivisibleBy(15, 3): 5
fareFor(70): 8
Once it passes, try two variations and predict each before running:
- Reorder the FizzBuzz chain. In
fizzbuzzWord, move the divisible-by-3 test (n % 3 === 0 → "Fizz") above the both-divisible test. Predict whatfizzbuzzWord(15)returns before running. 15 is divisible by 3 and by 5, but the chain returns on the first match — so it now answers"Fizz"and never reaches"FizzBuzz", and the first check fails. This is the order-matters point in your own hands. - Off-by-one in the count loop. In
countDivisibleBy, change the loop bound fromi <= limittoi < limit. Decide whatcountDivisibleBy(15, 3)returns before running. Stopping at 14 drops the multiple15itself, so the count comes back4instead of5and the check fails — the classic inclusive-vs-exclusive loop boundary.
Key Takeaways
- Use
if/elsestatements to make decisions in your code - Comparison operators (
===,!==,<,>,<=,>=) compare values - Logical operators (
&&,||,!) combine conditions forloops are best when you know how many times to repeatwhileloops are best when you repeat until a condition changesbreakexits a loop,continueskips to the next iteration
Next Steps
Congratulations! You've learned the fundamentals of control flow. Next, we'll explore data structures - how to work with collections of data like arrays and objects!
Pro Tip: When writing loops, always make sure your condition will eventually become false. Otherwise, you'll create an infinite loop that never stops! Also, practice reading other people's code to see different ways of solving problems with control flow.
Next lesson
Data Structures
Learn how to organize data with JavaScript arrays and objects. Covers destructuring, spread operator, and essential array methods.
18 min