Skip to content

JavaScript lesson 8 of 9

JavaScript For Loops and Iteration

Learn JavaScript loops from the ground up - the classic for loop, for...of, the forEach array method, getting both index and value with entries, and steering a loop with break and continue.

Published · Every example on this page was run before it was published.

An array can hold a hundred scores, and a string can hold a thousand characters, but so far the only way you have to look at them is one line of code per value. That does not scale, and it is not how programs are written. What you need is a way to say "do this same thing once for every value in here" — and that is exactly what a loop does. Loops are the point where your programs stop being lists of instructions and start being able to handle data of any size.

JavaScript actually gives you three distinct ways to loop, each suited to a different situation, and this lesson covers all three.

The Classic for Loop

The original loop, and still the right tool whenever you need to count through numbers yourself, is the three-part for loop:

JavaScript
for (let i = 0; i < 5; i++) {
  console.log(i);
}
Output
0
1
2
3
4

Read the three parts inside the parentheses in order. let i = 0 runs once, before the loop starts, creating a counter. i < 5 is the condition, checked before every single pass — the moment it is false, the loop stops. i++ runs after every pass, moving the counter forward. Because the condition is checked before the first pass too, a loop whose condition is already false never runs its body at all.

for...of: Looping Over Values Directly

Most of the time you don't actually want the counter — you want the values themselves. for...of walks any iterable — an array, a string, and several other collection types you'll meet later — and hands you one value per pass, with no counter to manage at all.

JavaScript
const chores = ["water plants", "wash dishes", "take out trash"];

for (const chore of chores) {
  console.log("Today I need to:", chore);
}
Output
Today I need to: water plants
Today I need to: wash dishes
Today I need to: take out trash

chores is the array being walked through, and chore is the loop variable — a name you invent, which JavaScript fills in with a different value on each pass. Declaring it with const is normal and correct here, even though it changes value every iteration: each pass creates a brand-new binding, so you are never actually reassigning the same chore, just creating a fresh one each time round.

Loops shine when you need to build up an answer across many values. A variable that collects a result as the loop runs is called an accumulator:

JavaScript
const prices = [4.5, 2.25, 10];
let total = 0;

for (const price of prices) {
  total += price;
}

console.log("Items:", prices.length);
console.log("Total:", total);
Output
Items: 3
Total: 16.75

Notice that total is created before the loop, with let because it genuinely needs to change. If it were created inside the loop body, it would reset to zero on every pass and the final answer would just be the last price.

A string is iterable too, and for...of on one hands you a single character per pass, left to right:

JavaScript
const word = "loop";

for (const letter of word) {
  console.log(letter);
}
Output
l
o
o
p

Combined with a condition, that is the foundation of nearly every text-processing task:

JavaScript
const name = "Jonathan";
let vowelCount = 0;

for (const character of name) {
  if ("aeiouAEIOU".includes(character)) {
    vowelCount++;
  }
}

console.log(name, "has", vowelCount, "vowels");
Output
Jonathan has 3 vowels

The forEach Method

Arrays offer a second way to loop, without writing a for statement at all. .forEach() is a method that takes a function and calls it once per element, automatically handing that function the value and its index:

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

colors.forEach((color, index) => {
  console.log(index, color);
});
Output
0 red
1 green
2 blue

.forEach() reads nicely for simple "do this to every item" tasks, and it gives you the index for free without any extra setup. But it comes with a sharp limitation worth knowing before you reach for it: the function you pass to .forEach() is an ordinary function call, not a loop from JavaScript's point of view, so break and continue are not allowed inside it at all — the code does not even run, because JavaScript refuses to parse it:

JavaScript
const numbers = [1, 2, 3, 4, 5];
numbers.forEach((n) => {
  if (n === 3) {
    break;
  }
  console.log(n);
});
Output
SyntaxError: Illegal break statement

If you might need to stop early, reach for for...of or a classic for loop instead of .forEach().

Steering a Loop: break and continue

By default a loop visits every value. Two keywords change that, and both work identically in a for...of loop and a classic for loop.

break stops the loop immediately and jumps to the code after it. Use it when you have found what you were looking for and there is no reason to keep checking:

JavaScript
const nums = [12, 7, 40, 3, 25];

for (const n of nums) {
  console.log("Checking", n);
  if (n > 30) {
    console.log("Found one over 30:", n);
    break;
  }
}
Output
Checking 12
Checking 7
Checking 40
Found one over 30: 40

The values 3 and 25 are never examined, because break ended the loop at 40.

continue skips the rest of the current pass and moves straight to the next value. The loop keeps going — only that one pass is cut short. It is the natural way to filter out values you want to ignore:

JavaScript
const readings = [3, -1, 8, -4, 5];
let total = 0;

for (const reading of readings) {
  if (reading < 0) {
    continue;
  }
  total += reading;
}

console.log("Total of valid readings:", total);
Output
Total of valid readings: 16

Getting the Index Too: entries()

Sometimes you genuinely need both the position and the value at once. You could go back to a classic for loop and index into the array yourself:

JavaScript
const items = ["pen", "notebook", "eraser"];

for (let i = 0; i < items.length; i++) {
  console.log(i, items[i]);
}
Output
0 pen
1 notebook
2 eraser

But .entries() does the same job more directly. It turns an array into a sequence of [index, value] pairs, which you can unpack straight into two loop variables using for...of:

JavaScript
const items = ["pen", "notebook", "eraser"];
for (const [index, item] of items.entries()) {
  console.log(index, item);
}
Output
0 pen
1 notebook
2 eraser

Reach for a plain for...of when you only need the values, and .entries() the moment you genuinely need the position too — it reads more clearly than manual indexing and cannot go off by one the way hand-written counter logic sometimes does.

A Worked Example

This program builds a short class report from two parallel arrays — names and scores — using .entries() to keep the two lined up, continue to skip a retake, and a second loop with break to find the first perfect score.

JavaScript
const students = ["Omar", "Priya", "Wei", "Sofia", "Liam"];
const scores = [76, 52, 95, 81, 100];

const passing = [];
let total = 0;

for (const [i, name] of students.entries()) {
  const score = scores[i];
  if (score < 60) {
    console.log(i + 1, name, "needs a retake");
    continue;
  }
  passing.push(name);
  total += score;
  console.log(i + 1, name, "scored", score);
}

console.log("Passing:", passing);
console.log("Average of passing scores:", total / passing.length);

for (const [i, name] of students.entries()) {
  if (scores[i] === 100) {
    console.log("Perfect score by", name);
    break;
  }
}
Output
1 Omar scored 76
2 Priya needs a retake
3 Wei scored 95
4 Sofia scored 81
5 Liam scored 100
Passing: [ 'Omar', 'Wei', 'Sofia', 'Liam' ]
Average of passing scores: 88
Perfect score by Liam

Here is what each part does. students and scores are two arrays holding related data in matching positions: scores[0] is Omar's score because students[0] is Omar. JavaScript has no single built-in function for walking two arrays together the way you might expect — the standard technique is exactly what this example does, looping by a shared index using .entries().

passing starts as an empty array and total starts at 0, both accumulators created before the loop so they survive across iterations. Inside the body, i + 1 turns the zero-based index into a human-friendly rank starting at 1. Any score below 60 prints a retake message and hits continue, which jumps to the next student without touching either accumulator — that is why Priya never appears in passing and her 52 never lands in total. Every other student is pushed onto passing, added into total, and printed.

After the loop, passing holds the four names that survived the filter, and dividing total by passing.length gives the average of exactly those four scores — not all five. The second loop is a search: it walks the pairs again looking for a perfect score, and break ends it the instant Liam is found, so nothing after that point is checked.

Common Mistakes

Using break or continue inside forEach

Covered above, and worth repeating because it is easy to forget under pressure: .forEach()'s callback is an ordinary function, and break and continue are only legal inside an actual loop. If you find yourself wanting to stop a .forEach() early, that is a sign to rewrite it as a for...of loop instead.

An off-by-one in the loop condition

JavaScript
const letters = ["a", "b", "c"];
for (let i = 0; i <= letters.length; i++) {
  console.log(letters[i]);
}
Output
a
b
c
undefined

letters.length is 3, and the valid indices are 0, 1, and 2 — using <= instead of < lets the loop run one extra time with i equal to 3, which is past the end of the array. Unlike some languages, that does not crash: letters[3] simply evaluates to undefined, which then prints as if it were a real value. An unexpected undefined in your output is one of the most common signs of an off-by-one loop condition. The fix is i < letters.length.

Assuming for...in gives you values

JavaScript
const totals = [10, 20, 30];
for (const index in totals) {
  console.log(typeof index, index);
}
Output
string 0
string 1
string 2

for...in exists, but it loops over an array's keys, not its values — and for an array, those keys come back as strings, not numbers. That second part is the dangerous one, because it can silently break arithmetic:

JavaScript
const totals = [10, 20, 30];
for (const index in totals) {
  console.log(index + 1);
}
Output
01
11
21

index holds the string "0", "1", "2" on each pass, and + between a string and a number concatenates rather than adds — exactly the trap from the lesson on arithmetic, showing up again here. for...of and .entries() hand you real values (and real numbers for indices), which is why they are the standard choice for arrays; save for...in for looping over the keys of a plain object.

Next Steps

Try the linked practice problem, two-number-sum. It hands you an array of numbers and a target, and asks you to find the pair that adds up to it — which is a loop inside a loop in the slow version, and a single for...of paired with an object lookup in the fast one, with break (or an early return) stopping the search the moment you have an answer.

Before you start, spend a few minutes in the JavaScript playground. Try changing a for loop's condition from < to <= on purpose and watch the extra undefined appear. Loop over an array with for...in and log typeof the loop variable, so that the string-versus-number trap becomes something you have seen for yourself rather than something you read about.

When you want a harder one

Interview-style problems graded against hidden tests — a big step up from the exercises. Come back to these when the ideas in this lesson feel comfortable rather than new.