Skip to main content

🔁 Lesson 6: Loops

Stop repeating yourself — let JavaScript do the repetition for you with loops that process data, count, and iterate.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Write for loops to repeat code a specific number of times
  • Use while and do...while loops for condition-based repetition
  • Iterate over arrays with for...of
  • Iterate over object keys with for...in
  • Control loop execution with break and continue
  • Avoid common pitfalls like infinite loops and off-by-one errors

Estimated Time: 50 minutes

Project: Build a star-rating display and a simple search filter

📑 In This Lesson

Introduction

Imagine you have an array of 100 products and you need to display each one. Without loops, you'd write 100 nearly identical lines of code. Loops let you write the instruction once and repeat it as many times as needed.

JavaScript gives you several loop types, each suited to different situations. By the end of this lesson, you'll know which one to reach for and why.

graph TD A["Start"] --> B{"More items?"} B -->|Yes| C["Process current item"] C --> D["Move to next item"] D --> B B -->|No| E["Done"] style B fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#1e293b style C fill:#ecfdf5,stroke:#22c55e,stroke-width:2px,color:#1e293b style E fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b

The for Loop

The for loop is the most common loop. It's ideal when you know how many times you want to repeat something.

Anatomy of a for Loop


//       initialization;  condition;    update
for (let i = 0;          i < 5;       i++) {
    console.log(`Iteration ${i}`);
}
// Output: 0, 1, 2, 3, 4  (runs 5 times)
                
Part What It Does Runs When
let i = 0Creates the counter variableOnce, before the loop starts
i < 5Checks if the loop should continueBefore each iteration
i++Updates the counterAfter each iteration
graph TD A["let i = 0"] --> B{"i < 5?"} B -->|Yes| C["Run loop body"] C --> D["i++"] D --> B B -->|No| E["Exit loop"] style A fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b style B fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#1e293b style C fill:#ecfdf5,stroke:#22c55e,stroke-width:2px,color:#1e293b

Looping Through Arrays by Index


const fruits = ["apple", "banana", "cherry", "date"];

for (let i = 0; i < fruits.length; i++) {
    console.log(`${i + 1}. ${fruits[i]}`);
}
// "1. apple"
// "2. banana"
// "3. cherry"
// "4. date"
                

Counting Backwards


// Countdown from 5 to 1
for (let i = 5; i >= 1; i--) {
    console.log(i);
}
console.log("Liftoff! 🚀");
                

Skipping Values


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

while & do...while

Use while when you don't know in advance how many iterations you need — the loop keeps running as long as the condition is true.

while Loop


let attempts = 0;
let password = "";

while (password !== "secret123") {
    attempts++;
    // Simulating user input
    password = attempts === 3 ? "secret123" : "wrong";
    console.log(`Attempt ${attempts}: ${password === "secret123" ? "✅ Correct!" : "❌ Wrong"}`);
}
console.log(`Logged in after ${attempts} attempts.`);
// Attempt 1: ❌ Wrong
// Attempt 2: ❌ Wrong
// Attempt 3: ✅ Correct!
// Logged in after 3 attempts.
                

do...while Loop

The do...while loop guarantees the body runs at least once because it checks the condition after each iteration.


let number;

do {
    number = Math.floor(Math.random() * 10) + 1;
    console.log(`Rolled: ${number}`);
} while (number !== 7);

console.log("You rolled a 7! 🎲");
// The loop always runs at least once, then keeps
// going until you roll a 7
                
graph TD A["while loop"] --> B{"Condition true?"} B -->|Yes| C["Run body"] C --> B B -->|No| D["Exit"] E["do...while loop"] --> F["Run body"] F --> G{"Condition true?"} G -->|Yes| F G -->|No| H["Exit"] style B fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#1e293b style G fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#1e293b style D fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b style H fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b

💡 for vs. while

Use for when you know how many times to loop (or when iterating over a collection with an index). Use while when the loop depends on a condition that could change unpredictably — like waiting for user input, a random result, or a network response.

for...of — Iterating Arrays

The for...of loop is the cleanest way to iterate over arrays (and other iterables like strings). It gives you the value directly — no index needed.


const colors = ["red", "green", "blue", "purple"];

for (const color of colors) {
    console.log(color);
}
// "red"
// "green"
// "blue"
// "purple"
                

Comparing for vs. for...of


const scores = [95, 87, 72, 100, 68];

// Traditional for — you manage the index yourself
for (let i = 0; i < scores.length; i++) {
    console.log(`Score ${i + 1}: ${scores[i]}`);
}

// for...of — cleaner when you don't need the index
for (const score of scores) {
    console.log(`Score: ${score}`);
}
                

Iterating Over Strings


const word = "Hello";

for (const char of word) {
    console.log(char);
}
// "H", "e", "l", "l", "o"
                

When You Need Both Index and Value


const tasks = ["Buy groceries", "Walk the dog", "Write code"];

// Use entries() to get both index and value
for (const [index, task] of tasks.entries()) {
    console.log(`${index + 1}. ${task}`);
}
// "1. Buy groceries"
// "2. Walk the dog"
// "3. Write code"
                

✅ Prefer for...of for Arrays

When you just need the values (no index manipulation), for...of is the modern, readable choice. Use a traditional for loop when you need the index for calculations or when looping backwards.

for...in — Iterating Object Keys

The for...in loop iterates over the keys (property names) of an object. It's designed for objects, not arrays.


const user = {
    name: "Ray",
    role: "Developer",
    level: "Senior",
    city: "Henderson"
};

for (const key in user) {
    console.log(`${key}: ${user[key]}`);
}
// "name: Ray"
// "role: Developer"
// "level: Senior"
// "city: Henderson"
                

❌ Don't Use for...in on Arrays

for...in iterates over keys, and for arrays, the keys are string indices ("0", "1", "2"). It can also pick up inherited properties. Always use for...of or a traditional for loop for arrays.


const colors = ["red", "green", "blue"];

// ❌ for...in on arrays — keys are strings!
for (const key in colors) {
    console.log(typeof key);  // "string" — not a number!
}

// ✅ for...of on arrays — gives you values
for (const color of colors) {
    console.log(color);  // "red", "green", "blue"
}
                    
Loop Best For Gives You
forCounting, index-based iterationControl over start, end, step
whileUnknown number of iterationsCondition-based looping
for...ofArrays, strings, iterablesValues directly
for...inObject propertiesKeys (property names)

break & continue

These keywords give you finer control over loop execution.

break — Exit Early

break immediately stops the loop and moves to the code after it.


// Find the first number greater than 50
const numbers = [12, 35, 8, 67, 42, 91, 23];

for (const num of numbers) {
    if (num > 50) {
        console.log(`Found it: ${num}`);
        break;  // Stop searching — we found what we need
    }
}
// "Found it: 67"
// (doesn't check 42, 91, or 23)
                

continue — Skip and Move On

continue skips the rest of the current iteration and jumps to the next one.


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

Real-World Example: Processing Valid Data


const inputs = ["hello", "", "world", null, "JavaScript", undefined, ""];

for (const input of inputs) {
    if (!input) {
        continue;  // Skip empty strings, null, undefined
    }
    console.log(`Processing: ${input.toUpperCase()}`);
}
// "Processing: HELLO"
// "Processing: WORLD"
// "Processing: JAVASCRIPT"
                
graph TD A["Start loop"] --> B{"More items?"} B -->|Yes| C{"Should skip?"} C -->|Yes — continue| B C -->|No| D["Process item"] D --> E{"Should exit?"} E -->|Yes — break| F["Exit loop"] E -->|No| B B -->|No| F style C fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#1e293b style E fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#1e293b style F fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b

Common Pitfalls

1. Infinite Loops

If the condition never becomes false, the loop runs forever and freezes your browser.


// ❌ INFINITE LOOP — i never changes!
// for (let i = 0; i < 10; ) {
//     console.log(i);  // Prints 0 forever
// }

// ❌ INFINITE LOOP — condition always true!
// let count = 0;
// while (count < 5) {
//     console.log(count);
//     // Forgot count++!
// }

// ✅ Always make sure the loop can exit
let count = 0;
while (count < 5) {
    console.log(count);
    count++;  // This makes the condition eventually false
}
                

❌ Browser Freeze Recovery

If you accidentally create an infinite loop and your browser freezes, close the tab (not the whole browser). In Chrome DevTools, you can also press the "Pause" button in the Sources panel to stop script execution.

2. Off-by-One Errors

Starting or ending at the wrong number — the most classic loop bug.


const items = ["a", "b", "c"];  // indices 0, 1, 2

// ❌ Off-by-one: uses <= instead of <
// for (let i = 0; i <= items.length; i++) {
//     console.log(items[i]);  // Last iteration: items[3] → undefined!
// }

// ✅ Correct: < length (not <=)
for (let i = 0; i < items.length; i++) {
    console.log(items[i]);  // "a", "b", "c"
}
                

3. Modifying an Array While Looping


// ❌ Dangerous — removing items shifts indices!
const nums = [1, 2, 3, 4, 5];
// for (let i = 0; i < nums.length; i++) {
//     if (nums[i] % 2 === 0) {
//         nums.splice(i, 1);  // Removes the element, but shifts everything
//     }
// }

// ✅ Safer — loop backwards or use filter()
const odds = nums.filter(n => n % 2 !== 0);
console.log(odds);  // [1, 3, 5]
                

Hands-on Exercise

🏋️ Exercise: Star Rating & Search Filter

Objective: Practice different loop types by building two mini-programs.

Part 1: Star Rating Display


// TODO: Write a function that takes a rating (1–5)
// and returns a string of stars
// Example: starRating(3) → "★★★☆☆"
// Example: starRating(5) → "★★★★★"

// Hint: Use a for loop to build the string
// Use "★" for filled stars and "☆" for empty stars
                    

Part 2: Simple Search Filter


// TODO: Given this array of products, find and log
// only the ones that contain the search term

// const products = [
//     "Wireless Mouse",
//     "USB Keyboard",
//     "Wireless Headphones",
//     "Monitor Stand",
//     "Wireless Charger"
// ];
// const searchTerm = "wireless";

// Expected output:
// "Found: Wireless Mouse"
// "Found: Wireless Headphones"
// "Found: Wireless Charger"
// "3 results found."

// Hint: Use .toLowerCase() on both the product name
// and search term for case-insensitive matching
                    
💡 Hint

Part 1: Use a for loop from 1 to 5. Inside the loop, use the ternary operator: i <= rating ? "★" : "☆". Append each star to a result string.

Part 2: Use for...of to iterate the products array. Use .toLowerCase().includes() to check if the product name contains the search term. Keep a counter for the number of matches.

✅ Solution

// Part 1: Star Rating Display
function starRating(rating) {
    let stars = "";
    for (let i = 1; i <= 5; i++) {
        stars += i <= rating ? "★" : "☆";
    }
    return stars;
}

console.log(starRating(1));  // "★☆☆☆☆"
console.log(starRating(3));  // "★★★☆☆"
console.log(starRating(5));  // "★★★★★"

// Part 2: Simple Search Filter
const products = [
    "Wireless Mouse",
    "USB Keyboard",
    "Wireless Headphones",
    "Monitor Stand",
    "Wireless Charger"
];
const searchTerm = "wireless";
let matchCount = 0;

for (const product of products) {
    if (product.toLowerCase().includes(searchTerm.toLowerCase())) {
        console.log(`Found: ${product}`);
        matchCount++;
    }
}

console.log(`${matchCount} result${matchCount === 1 ? "" : "s"} found.`);
                        

🎯 Quick Quiz

Question 1: How many times does this loop run?

for (let i = 0; i < 3; i++) {
    console.log(i);
}

Question 2: Which loop should you use to iterate over an array's values?

Question 3: What does continue do inside a loop?

Summary

🎉 Key Takeaways

  • for — best when you know how many iterations you need or need index control
  • while — best when the number of iterations depends on a changing condition
  • do...while — guarantees at least one iteration
  • for...of — cleanest way to iterate over arrays and strings (gives values)
  • for...in — iterates over object keys (don't use on arrays)
  • break exits a loop early; continue skips to the next iteration
  • Watch out for infinite loops and off-by-one errors

📚 Additional Resources

🚀 What's Next?

You can now make decisions and repeat actions. Next, you'll learn to package reusable logic into functions — the building blocks that keep your code organized, DRY, and powerful.