Skip to main content

3.2 Loops

What are Loops?​

Loops execute the same or similar operations multiple times. JavaScript provides various loop constructs.


for Loop​

The most basic loop, expressing initialization, condition, and increment in one line.

// Basic for loop
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}

// Reverse
for (let i = 4; i >= 0; i--) {
console.log(i); // 4, 3, 2, 1, 0
}

// Array traversal
const fruits = ["apple", "banana", "cherry"];
for (let i = 0; i < fruits.length; i++) {
console.log(`${i}: ${fruits[i]}`);
}

// Nested for: 2D array
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++) {
process.stdout.write(matrix[row][col] + " ");
}
console.log();
}

while Loop​

Repeats while condition is true.

let count = 0;
while (count < 5) {
console.log(count);
count++;
}

// Infinite loop + break
let input = "";
while (true) {
input = getNextInput();
if (input === "quit") break;
processInput(input);
}

do-while Loop​

Executes first, then checks condition. Always runs at least once.

let result;
do {
result = prompt("Enter a number (1-10):");
} while (isNaN(result) || result < 1 || result > 10);

for...of: Iterable Traversal​

Added in ES6, for...of iterates over arrays, strings, Maps, Sets, and other iterables.

// Array
const numbers = [10, 20, 30, 40, 50];
for (const num of numbers) {
console.log(num);
}

// With index using entries()
for (const [index, value] of numbers.entries()) {
console.log(`[${index}] ${value}`);
}

// String
for (const char of "Hello") {
console.log(char); // H, e, l, l, o
}

// Map
const map = new Map([["name", "Alice"], ["age", 25]]);
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}

// Set
const set = new Set([1, 2, 3, 2, 1]); // deduplication
for (const item of set) {
console.log(item); // 1, 2, 3
}

for...in: Object Property Enumeration​

const user = { name: "Alice", age: 25, city: "New York" };

for (const key in user) {
console.log(`${key}: ${user[key]}`);
}

Caution with for...in​

// Includes prototype chain properties!
// Use hasOwnProperty to filter

// Better approach: Object.keys or Object.entries
for (const key of Object.keys(user)) {
console.log(key); // Only own properties
}

for (const [key, value] of Object.entries(user)) {
console.log(`${key}: ${value}`);
}

forEach vs for...of​

const arr = [1, 2, 3, 4, 5];

// forEach: callback style
arr.forEach((item, index) => {
console.log(`${index}: ${item}`);
});
// Limitation: cannot use break, continue, or return (outer)

// for...of: iteration protocol
for (const item of arr) {
if (item === 3) break; // OK!
console.log(item);
}

// Async processing: for...of supports await
async function processItems(items) {
for (const item of items) {
await processItem(item); // Sequential processing
}
}

// forEach doesn't work properly with async/await
async function badAsync(items) {
items.forEach(async (item) => {
await processItem(item); // All start simultaneously!
});
// forEach doesn't wait for Promises
}

break and continue​

// break: immediately exits loop
const numbers = [1, 5, 3, 8, 2, 9, 4];
let target = -1;
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] > 7) {
target = numbers[i];
break;
}
}
console.log(target); // 8

// continue: skip current iteration
for (let i = 0; i < 10; i++) {
if (i % 2 === 0) continue; // skip evens
console.log(i); // 1, 3, 5, 7, 9
}

// Labels: control outer loop in nested loops
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
break outer; // exit outer loop
}
console.log(`${i},${j}`);
}
}

Pro Tips​

Loop Selection Guide​

// Iterate array elements → for...of or forEach
for (const item of array) { }
array.forEach(item => { });

// Transform array → map
const doubled = array.map(x => x * 2);

// Filter array → filter
const evens = array.filter(x => x % 2 === 0);

// Object properties → for...of + Object.entries
for (const [key, value] of Object.entries(obj)) { }

// Async sequential processing → for...of + await
for (const item of items) {
await process(item);
}

// Async parallel processing → Promise.all + map
await Promise.all(items.map(item => process(item)));