π 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
forloops to repeat code a specific number of times - Use
whileanddo...whileloops for condition-based repetition - Iterate over arrays with
for...of - Iterate over object keys with
for...in - Control loop execution with
breakandcontinue - 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
Adopting the DRY (Don't Repeat Yourself) principle is crucial for maintainable software. Manually writing identical instructions for collection itemsβsuch as products in an inventory or users in a listβis inefficient and prone to error.
Loops automate repetitive tasks, enabling efficient data processing and collection iteration. This lesson introduces various loop types, helping you select the appropriate approach for different requirements.
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 = 0 | Creates the counter variable | Once, before the loop starts |
i < 5 | Checks if the loop should continue | Before each iteration |
i++ | Updates the counter | After each iteration |
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
π‘ 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 |
|---|---|---|
for | Counting, index-based iteration | Control over start, end, step |
while | Unknown number of iterations | Condition-based looping |
for...of | Arrays, strings, iterables | Values directly |
for...in | Object properties | Keys (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"
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 controlwhileβ best when the number of iterations depends on a changing conditiondo...whileβ guarantees at least one iterationfor...ofβ cleanest way to iterate over arrays and strings (gives values)for...inβ iterates over object keys (don't use on arrays)breakexits a loop early;continueskips to the next iteration- Watch out for infinite loops and off-by-one errors
π Additional Resources
- MDN β Loops and Iteration
- javascript.info β Loops: while and for
- MDN β for...of
- MDN β for...in
π 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.