SKU // 24

JavaScript For Loop

The for loop is the workhorse of repetition. It packs the start, the condition, and the change into one line, so you can see the whole shape of the loop at a glance. When you know how many times something should happen, for is usually the right tool.

// Syntax

for (exp1; exp2; exp3) {
  // code block to be executed
}
Part Job Runs
exp1 (start)Sets up the counter: let i = 0Once, before anything else
exp2 (condition)Decides whether to run the block: i < 5Before every pass
exp3 (change)Moves the counter along: i++After every pass

The three parts are separated by semicolons, not commas.

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

// Step by Step

  1. let i = 0 runs once, before anything else
  2. i < 3 is checked. If it is false, the loop ends immediately
  3. The body runs
  4. i++ runs, then JavaScript jumps back to step 2

Tracing it by hand: i is 0 (print), 1 (print), 2 (print), 3 (condition fails, stop). The body ran three times. Tracing a loop on paper like this is the best way to predict what it will do.

// Counting Different Ways

The change step does not have to be i++. It can count down, count by twos, or anything else that moves toward the end:

// Count down
for (let i = 3; i > 0; i--) {
  console.log(i);
}
console.log("Liftoff");
3 2 1 Liftoff
// Count by twos
for (let i = 0; i <= 10; i += 2) {
  console.log(i);
}
0 2 4 6 8 10

// Looping Over an Array

const cars = ["BMW", "Volvo", "Saab", "Ford"];
let text = "";

for (let i = 0; i < cars.length; i++) {
  text += cars[i] + " ";
}
console.log(text);
BMW Volvo Saab Ford

// Building a Result

Loops often accumulate a value: a running total, a string, a count.

const prices = [4.50, 12.00, 3.25];
let total = 0;

for (let i = 0; i < prices.length; i++) {
  total += prices[i];
}
console.log("Total: $" + total.toFixed(2));
Total: $19.75
Tip
The accumulator (total) must be declared outside the loop. Declared inside, it would be reset to 0 on every pass and you would only ever see the last price.

// All Three Parts Are Optional

Each of the three expressions can be left out, as long as the semicolons stay. You will not do this often, but you will see it.

Leave out exp1 when the counter is already set before the loop:

let i = 2;
let text = "";
for (; i < cars.length; i++) {
  text += cars[i] + " ";
}
console.log(text);    // starts from index 2
Saab Ford

Leave out exp3 when the counter changes inside the body instead:

let i = 0;
for (; i < cars.length; ) {
  console.log(cars[i]);
  i++;
}

That is really a while loop wearing a for costume, and the next lesson shows the cleaner way to write it.

Leave out exp2 and there is no condition at all, so the loop never stops on its own. You must use break inside it (see JS Break), or the page freezes.

// Loop Scope: let vs var

Declare the counter with let, and it belongs to the loop only. Declare it with the old var, and it leaks out and overwrites any variable of the same name:

var i = 5;
for (var i = 0; i < 10; i++) {
  // some code
}
console.log(i);    // var: the loop redeclared the outer i

let j = 5;
for (let j = 0; j < 10; j++) {
  // some code
}
console.log(j);    // let: the outer j is untouched
10 5

This is the block scope rule from JS Let, applied to loops. Use let.

Watch out: the stray semicolon
for (let i = 0; i < 5; i++); { count++; } has a semicolon after the ). That semicolon is the loop's entire body: an empty statement, repeated 5 times. The block in braces is then an ordinary block that runs once, after the loop. No error, just a wrong answer. (It is the same trap as the stray semicolon after an if.)

// for...of: Loop Over Values

When you only need each value and not its position, for...of is cleaner. There is no counter and no index to get wrong:

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

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

Each pass, color holds the next value. It can be const because it is a fresh variable on every pass, never reassigned. It works on strings too, one character at a time:

for (const letter of "JS") {
  console.log(letter);
}
J S

// for...in: Loop Over Object Keys

An object stores values under names, like {name: "Alex", level: 4} (objects get their own section later). for...in visits each name (called a key):

const player = { name: "Alex", level: 4, hp: 80 };

for (const key in player) {
  console.log(key + " = " + player[key]);
}
name = Alex level = 4 hp = 80
Watch out: in vs of
Use for...in for objects only. On an array it gives you the index positions (as strings: "0", "1"...), not the values. Memory trick: of gives values of a list; in gives the keys in an object.

// Nested Loops

A loop inside a loop runs the inner loop completely for each single pass of the outer one. With 3 outer passes and 3 inner passes, the inner body runs 9 times:

for (let row = 1; row <= 3; row++) {
  let line = "";
  for (let col = 1; col <= 3; col++) {
    line += (row * col) + "\t";
  }
  console.log(line);
}
1 2 3 2 4 6 3 6 9

"\t" is a tab character, used here to line the columns up. Each loop needs its own counter name (row and col); reusing i for both would make the inner counter hide the outer one, and the table would come out wrong.

// Quick Check

What does this log?

for (let i = 10; i > 0; i -= 3) {
  console.log(i);
}
Show answer
10, 7, 4, 1. Next would be -2, which fails i > 0, so the loop stops.

Which header is written correctly?

  1. for (let i = 0, i < 5, i++)
  2. for (let i = 0; i < 5; i++)
  3. for let i = 0; i < 5; i++
  4. for (i < 5; let i = 0; i++)
Show answer
B. The three parts go in the order start; condition; change, separated by semicolons, all inside parentheses. A uses commas, C has no parentheses, and D has the parts in the wrong order.

You want to print every value in const pets = ["cat", "dog"]; and don't need the index. Which loop is the cleanest fit?

  1. for (const p in pets)
  2. for (const p of pets)
  3. while (pets)
  4. for (let i = 0; i <= pets.length; i++)
Show answer
B. for...of hands you each value directly. A gives the indexes ("0", "1"), C never ends (an array is always truthy), and D runs one time too many because of <=.

// Try It

  1. Click Open Playground and run it to print every odd number from 1 to 19. Then change it to count down from 10 to 0
  2. Sum the numbers 1 to 100 with an accumulator. (The answer is 5050.)
  3. Rewrite an array loop of your own using for...of
  4. Build a 5 by 5 multiplication table with nested loops
// Video Walkthroughs
Last updated: Oct 9, 2026, 11:56 PM ET