JavaScript · Beginner

Loops in JavaScript: for, while, for...of and for...in

9 min readUpdated September 24, 2026Every example verified

In short: A loop repeats a block of statements. A for loop counts with an index, a while loop runs until its condition becomes false, for...of visits each value of an array or string, and for...in visits an object's keys. break leaves a loop early and continue skips to the next round.

Repeating work

A loop runs the same block many times, either a known number of times, once per item of a collection, or until some condition changes. Choosing among JavaScript's loop statements is mostly a matter of which of those three you are asking.

The classic for loop has three parts in its header: an initialiser that runs once (let i = 0), a condition checked before every round (i < 5), and an update that runs after every round (i++). It is the loop for counting and for anything where you need the position. Declaring the counter with let in the header gives each round its own copy of the variable and keeps it out of the surrounding scope, which matters when a function inside the loop remembers it; the closures lesson shows why.

while (condition) checks the condition first and repeats the block as long as it stays true. The block must change something the condition depends on, or the loop never ends. It fits situations where the number of rounds is unknown: reading input until a sentinel line, halving a number until it is small. do { } while (condition) is the same but checks after the block, so the block always runs at least once.

for...of (ES2015) visits each value of an iterable, which includes arrays, strings, Maps and Sets. It is the loop to use when you have a collection and do not need the index, because there is no counter to get wrong. for...in visits the enumerable property keys of an object, as strings. It is for plain objects, not arrays: on an array it yields index strings such as "0" and can include inherited properties, so use for...of or a counted loop for arrays.

Two statements change the flow inside any loop. break ends the loop immediately and execution continues after it. continue abandons the current round and goes straight to the next condition check or the next item. Inside nested loops, both apply to the innermost loop only.

Reading input is where beginners meet loops first. readline() returns null when the input is exhausted, so while ((line = readline()) !== null) reads every line, and a for loop with a count read from the first line reads a known number of them.

Syntax

 JavaScript · syntax
for (let i = 0; i < n; i++) {   // init; condition; update
  block;
}

while (condition) {              // checked before each round
  block;                         // must move toward making condition false
}

do {
  block;                         // runs at least once
} while (condition);

for (const item of array) { }    // each value of an array, string, Map, Set
for (const key in object) { }    // each own enumerable key of an object

break;                           // leave the loop now
continue;                        // skip to the next round

let line;
while ((line = readline()) !== null) {   // every line of input
  block;
}

The extra parentheses in (line = readline()) !== null are required: they make the assignment happen before the comparison.

Which loop when

SituationLoop
Repeat a known number of times, or need the indexfor (let i = 0; ...)
Each value of an array or string, no index neededfor...of
Each key of a plain objectfor...in (or Object.keys with for...of)
Repeat until a condition changeswhile
Body must run at least oncedo...while
Read input until it ends or a sentinel line arriveswhile with readline() and break

Counting with for: readings, an average and a countdown

Four temperature readings are visited by index, then a second loop counts down in steps of three.

 JavaScript
const readings = [12.5, 13.25, 12.75, 14.5];
let total = 0;
for (let i = 0; i < readings.length; i++) {
  total += readings[i];
  console.log("Reading " + (i + 1) + ": " + readings[i]);
}
console.log("Average:", (total / readings.length).toFixed(2));

for (let n = 10; n > 0; n -= 3) {
  console.log(n);
}

Output

Reading 1: 12.5
Reading 2: 13.25
Reading 3: 12.75
Reading 4: 14.5
Average: 13.25
10
7
4
1

i runs from 0 to 3 because the condition i < readings.length stops it before 4; i + 1 is printed so the readings are numbered from one. total is an accumulator: it starts at 0 and each round adds one reading, the shape behind every sum and average. The second loop shows that the update can be any expression: n -= 3 gives 10, 7, 4, 1 and stops when n would be -2.

while and do...while

A savings plan runs until a target is reached; a do...while runs its block once even though its condition is false from the start.

 JavaScript
let saved = 0;
let weeks = 0;
while (saved < 250) {
  saved += 60;
  weeks++;
}
console.log("Weeks needed:", weeks, "saved:", saved);

let n = 100;
let halvings = 0;
while (n > 5) {
  n = n / 2;
  halvings++;
}
console.log("Halved", halvings, "times, ending at", n);

let attempts = 0;
do {
  attempts++;
  console.log("Attempt", attempts);
} while (attempts < 1);

Output

Weeks needed: 5 saved: 300
Halved 5 times, ending at 3.125
Attempt 1

The first loop has no way of knowing in advance how many rounds it needs; it keeps adding 60 until saved < 250 fails, which happens after the fifth week. The second halves 100 to 50, 25, 12.5, 6.25 and 3.125, five rounds, and stops because 3.125 is not greater than 5. The do...while block runs once and then tests attempts < 1, which is already false, so it ends; a plain while with the same condition would never have run the block at all.

Reading input until a sentinel, with continue, break, for...of and for...in

The input lines are 4, -2, 9, done and 7. Negative values are skipped and reading stops at the word done.

 JavaScript
const kept = [];
while (true) {
  const line = readline();
  if (line === null || line === "done") {
    break;
  }
  const value = Number(line);
  if (value < 0) {
    continue;
  }
  kept.push(value);
}
console.log("Kept:", kept);

for (const v of kept) {
  if (v > 5) {
    console.log("First value above 5:", v);
    break;
  }
}

const stock = { bolts: 40, nuts: 12 };
for (const key in stock) {
  console.log(key + " -> " + stock[key]);
}

for (const ch of "ab") {
  console.log(ch);
}

Input given to the program: 4-29done7

Output

Kept: [ 4, 9 ]
First value above 5: 9
bolts -> 40
nuts -> 12
a
b

The first loop is written as while (true) because its exit test sits in the middle: it must read a line before it can decide whether to stop. Testing for null as well as "done" means the loop also ends safely if the sentinel never arrives. continue skips the push for -2 and goes back to the next readline(). The 7 after done is never read. The for...of loop leaves as soon as it finds 9, the for...in loop gives the keys of the object (and the value is fetched with stock[key]), and a string is iterable one character at a time.

Common mistakes

  • Looping with <= length

    Why it goes wrong: Indexes run from 0 to length - 1, so for (let i = 0; i <= items.length; i++) visits one index too many and reads undefined on the last round; arithmetic on it gives NaN.

    Fix: Use i < items.length, or a for...of loop that cannot go out of range.

     JavaScript · fix
    for (let i = 0; i < items.length; i++) {
      console.log(items[i]);
    }
  • A while loop whose condition never changes

    Why it goes wrong: while (count < 5) { console.log(count); } never increments count, so it prints forever and the program is killed by the runner's time limit.

    Fix: Make sure the block changes something the condition depends on, or switch to a counted for loop when the number of rounds is known.

  • Using for...in on an array

    Why it goes wrong: It yields the indexes as strings, so key + 1 gives "01" rather than 1, and it can also visit properties added to arrays by libraries.

    Fix: Use for...of for the values, or a counted for loop when you need numeric indexes.

     JavaScript · fix
    for (const value of [10, 20]) {
      console.log(value);
    }
  • Removing items from an array while looping over it by index

    Why it goes wrong: Each removal shifts the later items one place left, so the item that followed the removed one is skipped.

    Fix: Build a new array with filter, or loop backwards from the last index so removals do not affect unvisited items.

     JavaScript · fix
    const readings = [3, -1, 4, -2];
    const positive = readings.filter((r) => r >= 0);
    console.log(positive); // [ 3, 4 ]

Where you use this

Nearly every exercise reads several lines of input, and a loop is how they are read. When the first line says how many follow, a counted for reads exactly that many; when the input simply ends, the while ((line = readline()) !== null) pattern reads until null. Inside the loop an accumulator collects the answer: a running total, a count of matches, the largest value seen so far, or an array of parsed values to process afterwards. Read, convert, update is the skeleton behind sums, averages and maximums in every language.

 JavaScript · in practice
let line;
let count = 0;
let total = 0;
while ((line = readline()) !== null) {
  total += Number(line);
  count++;
}
console.log(count, total);

Key points

  • for (let i = 0; i < n; i++) counts; for...of visits values; for...in visits object keys; while repeats until a condition fails.
  • Array indexes run from 0 to length - 1, so the condition is <, not <=.
  • A while body must change what the condition depends on, or it never ends.
  • break leaves the loop; continue jumps to the next round; both affect only the innermost loop.
  • readline() returns null at the end of input; test for it to read every line.
  • Do not use for...in on arrays and do not remove items from an array you are indexing through.

Try it yourself

The first input line says how many numbers follow. Read them in a loop and print the largest. The starter prints null until you fill in the loop.

Your program
const n = Number(readline());
let largest = null;
// read n numbers and keep the largest in largest
console.log(largest);
Input the program receives: 4 ↵ 8 ↵ 15 ↵ 3 ↵ 11
Expected output: 15

Practise this

Open the JavaScript playground

Frequently asked questions

What is the difference between for...of and for...in in JavaScript?

for...of iterates over the values of an iterable: the elements of an array, the characters of a string, the entries of a Map or Set. for...in iterates over the enumerable property names of an object, as strings, including names inherited from its prototype. Use for...of for arrays and strings and for...in (or Object.keys) for plain objects.

How do I get the index inside a for...of loop?

Loop over array.entries(), which yields index and value pairs: for (const [i, value] of array.entries()), using the array destructuring covered in the destructuring lesson. Alternatively, array.forEach((value, i) => ...) passes the index as the second argument, or use a counted for loop.

How do I read all input lines in JavaScript on this site?

Call readline() in a loop until it returns null: let line; while ((line = readline()) !== null) { ... }. If you prefer the whole input at once, readAll() returns the unread remainder as one string, which you can split on line breaks.

Progress is stored only in this browser.

How this page was checked. Every program on it was run with Node.js 22 at build time; runs in your browser in an isolated Web Worker by the publishing checks, and the output shown is what it printed. The Run buttons execute the same code on your device; nothing you type is sent anywhere.