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

Lesson 8 of 10

On this page

A loop repeats a block of code — once per item in a list, once per second, or until some condition stops being true. JavaScript gives you several loop forms; the trick is picking the one that says most clearly what you’re trying to do.

for...of — looping over the values in a collection

This is the loop you’ll reach for most often when you have an array (or any other collection of values) and want to do something with each item:

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

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

It reads almost like English — “for [each] color of colors” — and it hands you each value directly, with no counter or indexing to manage.

The classic counting for loop

When you need the position of each item, or you’re not iterating over a collection at all — just repeating something a fixed number of times — the traditional three-part for loop is still the right tool:

for (let i = 0; i < 5; i++) {
    console.log(`Attempt ${i + 1}`);
}
// "Attempt 1"
// "Attempt 2"
// ... up through "Attempt 5"

Breaking down the syntax — the parentheses hold three parts separated by semicolons:

while and do...while — looping until a condition changes

Use while when you don’t know in advance how many times you’ll loop — only that you should keep going while some condition holds:

let attempts = 0;

while (attempts < 3) {
    console.log(`Trying... (${attempts + 1})`);
    attempts++;
}

do...while is a small variation that always runs the body at least once, checking the condition only afterward — handy for things like “ask the user for input, and keep asking until they give a valid answer”:

let input;
do {
    input = getNextInput(); // pretend this asks the user something
} while (!isValid(input));

break and continue — controlling a loop mid-flight

Inside any loop, break stops it immediately, and continue skips ahead to the next iteration without finishing the current one:

const numbers = [4, 9, 15, 6, 2];

for (const number of numbers) {
    if (number > 10) break;     // stop entirely once we hit a big number
    if (number % 2 !== 0) continue; // skip odd numbers
    console.log(number);
}
// 4

Less common: for...in

for...in loops over the keys of an object:

const user = { name: "Ada", role: "admin" };

for (const key in user) {
    console.log(key); // "name", then "role"
}

It’s worth recognizing, but as the Objects lesson explains, Object.keys (and Object.entries) are the more common modern choice for working with an object’s properties — they avoid a quirk of for...in where it can also visit inherited properties you didn’t intend to include.

The old way of doing things

Before for...of and array methods like .map/.forEach were common, every loop over an array used a counter and the array’s .length:

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

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

This is the same classic for loop shown above, just aimed at an array instead of a fixed count. It works, but it requires you to manage an extra variable (i), index into the array yourself (colors[i]), and get the start, stop, and step exactly right — a frequent source of subtle “off-by-one” bugs (looping one time too many or too few).

for...of removes the counter and indexing entirely — you just say what you want (“each color”) and let JavaScript handle the bookkeeping. That’s why it, along with .map/.filter/.forEach from the Arrays lesson, has become the default way to loop over collections, while the classic counting for loop is reserved for the cases that genuinely need a counter or a fixed number of repetitions.