Loops: for, while, forEach, for...of
Loops: for, while, forEach, for...of
Loops repeat code until a condition is met. JavaScript has more loop types than most languages — each suited for a different situation. Choosing the right one makes your code more readable and often faster.
The Classic for Loop
// for (initialization; condition; update)
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
// Counting down
for (let i = 10; i > 0; i--) {
console.log(i); // 10, 9, 8 ... 1
}
// Iterating arrays by index
const fruits = ["apple", "banana", "cherry"];
for (let i = 0; i < fruits.length; i++) {
console.log(`${i}: ${fruits[i]}`);
}
// Nested loops — matrix operations
const matrix = [[1,2,3],[4,5,6],[7,8,9]];
for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) {
console.log(matrix[row][col]);
}
}
while Loop
Use while when you don't know upfront how many iterations you need:
// Basic while
let count = 0;
while (count < 5) {
console.log(count);
count++;
}
// Waiting for user input (in Node.js CLI)
let attempts = 0;
while (attempts < 3) {
const guess = getGuess();
if (guess === secretNumber) {
console.log("Correct!");
break;
}
attempts++;
}
// Polling pattern
async function waitForData() {
let data = null;
while (!data) {
data = await fetchData();
if (!data) await sleep(1000); // Wait before retrying
}
return data;
}
do...while Loop
Executes the body at least once, then checks the condition:
let input;
do {
input = prompt("Enter a number between 1 and 10:");
} while (input < 1 || input > 10);
// Useful for: menus, retry logic, first-run scenarios
let retries = 0;
do {
success = attemptConnection();
retries++;
} while (!success && retries < 3);
for...of Loop
The modern way to iterate over any iterable (arrays, strings, Maps, Sets):
const colors = ["red", "green", "blue"];
for (const color of colors) {
console.log(color); // no index needed
}
// Strings are iterable
for (const char of "hello") {
console.log(char); // h, e, l, l, o
}
// With index using entries()
for (const [index, value] of colors.entries()) {
console.log(`${index}: ${value}`);
}
// Maps
const scores = new Map([["Alice", 95], ["Bob", 87]]);
for (const [name, score] of scores) {
console.log(`${name}: ${score}`);
}
// Sets
const uniqueIds = new Set([1, 2, 3, 2, 1]);
for (const id of uniqueIds) {
console.log(id); // 1, 2, 3
}
for...in Loop
Iterates over the enumerable property keys of an object. Avoid using it on arrays:
const person = { name: "Alice", age: 30, city: "NYC" };
for (const key in person) {
console.log(`${key}: ${person[key]}`);
}
// name: Alice
// age: 30
// city: NYC
// Warning: for...in on arrays includes prototype properties
// Use for...of or forEach for arrays instead
Array Methods: forEach, map, filter, reduce
These are not traditional loops but they process arrays declaratively:
const numbers = [1, 2, 3, 4, 5];
// forEach — run a function for each element, no return value
numbers.forEach((num, index) => {
console.log(`${index}: ${num}`);
});
// map — transform each element into a new array
const doubled = numbers.map(n => n * 2); // [2, 4, 6, 8, 10]
// filter — keep elements that pass the test
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]
// reduce — accumulate to a single value
const sum = numbers.reduce((total, n) => total + n, 0); // 15
// Chaining
const result = numbers
.filter(n => n > 2) // [3, 4, 5]
.map(n => n ** 2) // [9, 16, 25]
.reduce((sum, n) => sum + n, 0); // 50
break and continue
// break — exit the loop immediately
for (let i = 0; i < 10; i++) {
if (i === 5) break;
console.log(i); // 0, 1, 2, 3, 4
}
// continue — skip current iteration, continue loop
for (let i = 0; i < 10; i++) {
if (i % 2 === 0) continue;
console.log(i); // 1, 3, 5, 7, 9
}
// Labels — break out of nested loops (use sparingly)
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (j === 1) break outer;
console.log(i, j);
}
}
// 0 0 ← stops when j hits 1 in first outer iteration
Performance: Which Loop Is Fastest?
For raw speed on large arrays: for > for...of > forEach > map/filter.
const arr = new Array(1_000_000).fill(1);
// Fastest for pure iteration
for (let i = 0; i < arr.length; i++) { /* */ }
// More readable, slightly slower
for (const item of arr) { /* */ }
// Slowest but declarative — preferred for most cases
arr.forEach(item => { /* */ });
In practice, the difference only matters for hot loops processing millions of items. Write readable code first and optimize only when profiling shows a bottleneck.
Common Patterns
// Loop with index + value
fruits.forEach((fruit, i) => console.log(`${i + 1}. ${fruit}`));
// Build an array of results
const squares = Array.from({length: 10}, (_, i) => (i + 1) ** 2);
// [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// Find first match (stops early)
const target = users.find(u => u.id === 42);
// Check if any/all match
const hasAdmin = users.some(u => u.role === "admin");
const allActive = users.every(u => u.isActive);
// Async iteration (await inside loop)
for (const userId of userIds) {
const user = await fetchUser(userId); // works! sequential
console.log(user.name);
}
// Parallel async (all at once — much faster)
const users = await Promise.all(userIds.map(id => fetchUser(id)));
Next lesson: Functions — declarations, expressions, arrow functions, and the critical difference between them.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises