Skip to content

Control Flow and Loops

💡
Before you start

You need Node installed, and to know how to run a .js file. If node --version in a terminal prints a version number, you are ready. If it does not — or if you have never opened a terminal — do Getting Started with JavaScript first; it installs Node and runs your first program in about fifteen minutes. Nothing else is needed.

If/Else Statements

The if statement lets your program make decisions. If a condition is true, a block of code runs. Unlike Python which uses indentation to define blocks, JavaScript uses curly braces { }.

const age = 18;

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

// if...else
if (age >= 18) {
    console.log("You can vote.");
} else {
    console.log("You cannot vote yet.");
}

// if...else if...else
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");
}
// Output: "Grade: B"

Logical Operators in Conditions

const age = 25;
const hasLicense = true;
const isSuspended = false;

// AND (&&) — both conditions must be true
if (age >= 16 && hasLicense) {
    console.log("You can drive.");
}

// OR (||) — at least one condition must be true
if (age < 13 || age > 65) {
    console.log("Discounted ticket.");
}

// NOT (!) — inverts a boolean
if (!isSuspended) {
    console.log("Account is active.");
}

// Combining operators
if (age >= 16 && hasLicense && !isSuspended) {
    console.log("You are cleared to drive.");
}

Switch Statements

Use switch when you need to compare a single value against many possible options. It is cleaner than a long chain of if...else if statements.

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("Almost the weekend!");
        break;
    case "Saturday":
    case "Sunday":
        console.log("Weekend!");
        break;
    default:
        console.log("Not a valid day.");
}
// Output: "Start of the work week."
⚠️
Don't forget break!

Without break, JavaScript "falls through" to the next case and keeps executing. This is intentional for grouping cases (like Tuesday/Wednesday/Thursday above), but forgetting break is a common source of bugs.

// Practical example: HTTP status codes
const status = 404;

switch (status) {
    case 200:
        console.log("OK — request succeeded.");
        break;
    case 301:
        console.log("Moved Permanently.");
        break;
    case 404:
        console.log("Not Found.");
        break;
    case 500:
        console.log("Internal Server Error.");
        break;
    default:
        console.log(`Unknown status: ${status}`);
}
// Output: "Not Found."

Ternary Operator

The ternary operator is a shorthand for simple if...else statements. It fits on one line and is useful for assigning values conditionally:

// Syntax: condition ? valueIfTrue : valueIfFalse

const age = 20;
const status = age >= 18 ? "adult" : "minor";
console.log(status); // "adult"

// Equivalent if...else:
// let status;
// if (age >= 18) {
//     status = "adult";
// } else {
//     status = "minor";
// }

// Common uses
const score = 85;
const grade = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : "F";

const items = 3;
console.log(`You have ${items} item${items === 1 ? "" : "s"}.`);
// "You have 3 items."

// In template literals
const loggedIn = true;
console.log(`Welcome${loggedIn ? ", user" : ""}!`);
// "Welcome, user!"

For Loops

The classic for loop repeats a block of code a specific number of times. It has three parts: initialization, condition, and update.

// Basic for loop
for (let i = 0; i < 5; i++) {
    console.log(i);
}
// 0, 1, 2, 3, 4

// Counting by twos
for (let i = 0; i <= 10; i += 2) {
    console.log(i);
}
// 0, 2, 4, 6, 8, 10

// Counting backwards
for (let i = 5; i > 0; i--) {
    console.log(i);
}
// 5, 4, 3, 2, 1

// Looping through an array by index
const fruits = ["apple", "banana", "cherry"];
for (let i = 0; i < fruits.length; i++) {
    console.log(`${i}: ${fruits[i]}`);
}
// "0: apple"
// "1: banana"
// "2: cherry"

Practical Example: Building a Multiplication Table

const number = 7;
for (let i = 1; i <= 10; i++) {
    console.log(`${number} x ${i} = ${number * i}`);
}
// 7 x 1 = 7
// 7 x 2 = 14
// ... up to 7 x 10 = 70

While and Do-While Loops

while Loop

A while loop repeats as long as its condition is true. Use it when you don't know in advance how many times you need to loop.

// Count up to a threshold
let count = 0;
while (count < 5) {
    console.log(count);
    count++;
}
// 0, 1, 2, 3, 4

// Practical: halving a number until it's below 1
let value = 100;
let steps = 0;
while (value >= 1) {
    value = value / 2;
    steps++;
}
console.log(`Took ${steps} steps to go below 1.`);
// "Took 7 steps to go below 1."
⚠️
Watch out for infinite loops!

If the condition never becomes false, your program will hang. Always make sure something inside the loop is moving toward the exit condition.

do...while Loop

A do...while loop always runs at least once, then checks the condition before repeating:

// Runs at least once even if condition is false
let input;
do {
    input = prompt("Enter 'quit' to exit:");
    console.log(`You entered: ${input}`);
} while (input !== "quit");

// Practical: generating a random number until we get one above 0.9
let random;
let attempts = 0;
do {
    random = Math.random();
    attempts++;
} while (random < 0.9);
console.log(`Got ${random.toFixed(4)} after ${attempts} attempts.`);

for...of and for...in

💡
for...of vs for...in — know the difference

for...of iterates over values and works with arrays, strings, Maps, Sets, and other iterables. for...in iterates over keys (property names) and is designed for objects. Using for...in on arrays is a common mistake — it iterates over index strings and can include inherited properties.

for...of — Iterate Over Values

// Arrays — get each value directly
const fruits = ["apple", "banana", "cherry"];
for (const fruit of fruits) {
    console.log(fruit);
}
// "apple", "banana", "cherry"

// Strings — iterate over characters
const word = "Hello";
for (const char of word) {
    console.log(char);
}
// "H", "e", "l", "l", "o"

// With array destructuring
const entries = [["name", "Alice"], ["age", 25]];
for (const [key, value] of entries) {
    console.log(`${key}: ${value}`);
}
// "name: Alice", "age: 25"

for...in — Iterate Over Object Keys

// Objects — get each property name
const user = {
    name: "Alice",
    age: 25,
    city: "London"
};

for (const key in user) {
    console.log(`${key}: ${user[key]}`);
}
// "name: Alice"
// "age: 25"
// "city: London"

// Why NOT to use for...in with arrays:
const colors = ["red", "green", "blue"];
for (const index in colors) {
    console.log(typeof index); // "string" — not a number!
    console.log(index);        // "0", "1", "2" — string keys
}
// Use for...of instead for arrays

Break and Continue

break exits a loop entirely. continue skips the current iteration and moves to the next one.

break — Exit Early

// Find the first negative number
const numbers = [3, 7, -2, 8, -5, 1];
let firstNegative = null;

for (const num of numbers) {
    if (num < 0) {
        firstNegative = num;
        break; // stop searching
    }
}
console.log(firstNegative); // -2

// Search for a user
const users = ["Alice", "Bob", "Charlie", "Diana"];
for (let i = 0; i < users.length; i++) {
    if (users[i] === "Charlie") {
        console.log(`Found Charlie at index ${i}`);
        break;
    }
}

continue — Skip This Iteration

// Print only even numbers
for (let i = 0; i < 10; i++) {
    if (i % 2 !== 0) {
        continue; // skip odd numbers
    }
    console.log(i);
}
// 0, 2, 4, 6, 8

// Skip blank entries
const data = ["Alice", "", "Bob", "", "", "Charlie"];
for (const name of data) {
    if (name === "") {
        continue; // skip empty strings
    }
    console.log(`Processing: ${name}`);
}
// "Processing: Alice"
// "Processing: Bob"
// "Processing: Charlie"

Labeled Statements (Advanced)

// Break out of nested loops using labels
outer: for (let i = 0; i < 3; i++) {
    for (let j = 0; j < 3; j++) {
        if (i === 1 && j === 1) {
            break outer; // breaks the outer loop, not just inner
        }
        console.log(`i=${i}, j=${j}`);
    }
}
// "i=0, j=0"
// "i=0, j=1"
// "i=0, j=2"
// "i=1, j=0"
// (stops here)

Now Do It Yourself: Five Steps

Decisions and loops, plus the comparison rule that causes more JavaScript bugs than anything else. Every output below is exactly what Node printed.

1
Make a decision

Go: open a terminal, run cd, and create flow.js.

Do: type these eight lines and run node flow.js.

const score = 72;
if (score >= 90) {
  console.log("A");
} else if (score >= 70) {
  console.log("B");
} else {
  console.log("C");
}

You should see: a single B. Tests run top to bottom and stop at the first true one. Unlike Python, the braces do the grouping and the indentation is only for humans — but write it neatly anyway, because the next person reading it is you.

If not: SyntaxError: Unexpected token usually means a missing brace or a missing bracket around the condition. JavaScript needs both: if (condition) { ... }.

2
Meet == and why you should not use it

Go: same file, replace the contents.

Do: type these three lines and run it.

console.log(0 == "0");
console.log(0 === "0");
console.log([] == false);

You should see: true, false, true. Read the third one again: an empty array equals false. == converts types before comparing and the rules are genuinely strange; === compares value and type and has no surprises.

If not: nothing to fix — the lesson is the rule: always write === unless you have a specific reason not to. The one common exception is value == null, which usefully catches both null and undefined at once.

3
Loop over a list

Go: same file, replace the contents.

Do: type these three lines and run it.

for (const name of ["Alice", "Bob"]) {
  console.log("Hello,", name);
}

You should see: Hello, Alice then Hello, Bob. for...of gives you each value and is what you want almost every time.

If not: if you get 0 and 1 instead of names, you wrote for...in. That gives you the keys — the positions — not the values. The two differ by two letters and do completely different things, which is exactly why the mistake is so easy.

4
Count, and build up a total

Go: same file, replace the contents.

Do: type these five lines and run it.

let total = 0;
for (let i = 1; i <= 5; i++) {
  total += i;
}
console.log(total);

You should see: 15 — 1+2+3+4+5. The three parts inside the brackets are: where to start, how long to keep going, and what to do each time round.

If not: if you get 10, your condition is i < 5 rather than i <= 5, so it stops one short. That off-by-one is the most common loop bug there is; when a total looks slightly wrong, check the comparison before anything else.

5
Put a decision inside a loop

Go: same file, replace the contents.

Do: type these eight lines and run it.

const scores = [95, 72, 58, 88];
for (const s of scores) {
  if (s >= 90) {
    console.log(s, "A");
  } else if (s >= 70) {
    console.log(s, "B");
  } else {
    console.log(s, "C");
  }
}

You should see: 95 A, 72 B, 58 C, 88 B. A loop with a decision inside it is most of everyday programming.

If not: if only one line prints, a brace closed the loop earlier than you meant. Count them, or let your editor do it — most highlight the matching brace when your cursor is on one, which is the fastest way to see where a block really ends.

🎉
Check yourself before moving on

Without scrolling up: why is 0 == "0" true while 0 === "0" is false? Answer: == converts the types before comparing, so the text "0" becomes the number 0. === compares type as well as value, so a string is never equal to a number.

Now do it without the page: change step 5 to also print how many students got an A. One variable before the loop, one ++ inside the right branch — the shape from step 4, placed inside step 5.

Summary

  • if/else if/else — make decisions based on conditions
  • switch — compare one value against many options (don't forget break!)
  • condition ? a : b — ternary operator for inline conditionals
  • for loop — repeat a known number of times
  • while — repeat while a condition is true
  • do...while — always runs at least once
  • for...of — iterate over values (arrays, strings)
  • for...in — iterate over keys (objects)
  • break — exit a loop early; continue — skip to next iteration
🎉
Control flow mastered!

You can now make decisions and repeat actions in JavaScript. Next up: functions — reusable blocks of code that make your programs modular and organized.