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)));