Welcome back! 👋 In the previous lesson, you mastered arrays and their built-in methods. Now let's put arrays and loops together — because in real JavaScript, arrays and loops are inseparable!
Almost everything you do with an array involves some kind of iteration — displaying a list, searching for an item, calculating a total, building a new collection, or processing incoming data. This lesson covers every pattern you'll use in real projects.
Let's dive in!
Why Loops with Arrays?
Arrays store collections of data — but data is only useful when you can work through it. Loops are how you do that.
let students = ["Mihir", "Priya", "Rahul", "Sara", "Arjun"];
// Without a loop — you'd have to write each line manually
console.log(students[0]);
console.log(students[1]);
// ... not practical for 100 students!
// With a loop — handle any size array in 3 lines ✅
for (let student of students) {
console.log(student);
}The 4 Main Ways to Loop Over an Array
1. for Loop — When You Need the Index
let fruits = ["Apple", "Banana", "Mango", "Orange"];
for (let i = 0; i < fruits.length; i++) {
console.log(`${i + 1}. ${fruits[i]}`);
}
// Output:
// 1. Apple
// 2. Banana
// 3. Mango
// 4. OrangeBest when: you need the index, need to loop backwards, or need to modify array elements.
2. for...of — When You Just Need the Value
let fruits = ["Apple", "Banana", "Mango", "Orange"];
for (let fruit of fruits) {
console.log(fruit);
}
// Output:
// Apple
// Banana
// Mango
// OrangeBest when: you only need the value — cleanest and most readable option.
3. forEach() — Callback Style
let fruits = ["Apple", "Banana", "Mango"];
fruits.forEach((fruit, index) => {
console.log(`${index + 1}. ${fruit}`);
});Best when: you want a clean callback style without managing a loop manually.
4. for...of with entries() — Value and Index Together
let fruits = ["Apple", "Banana", "Mango"];
for (let [index, fruit] of fruits.entries()) {
console.log(`${index + 1}. ${fruit}`);
}Best when: you need both the index and value in a for...of style.
Side by Side Comparison
let colors = ["Red", "Green", "Blue"];
// 1. for loop
for (let i = 0; i < colors.length; i++) {
console.log(i, colors[i]); // 0 Red, 1 Green, 2 Blue
}
// 2. for...of
for (let color of colors) {
console.log(color); // Red, Green, Blue
}
// 3. forEach
colors.forEach((color, i) => console.log(i, color)); // 0 Red, 1 Green, 2 Blue
// 4. for...of + entries()
for (let [i, color] of colors.entries()) {
console.log(i, color); // 0 Red, 1 Green, 2 Blue
}| Loop | Index? | Value? | Can break? | Best for |
|---|---|---|---|---|
for | ✅ | ✅ | ✅ | Index control, mutation |
for...of | ❌ | ✅ | ✅ | Clean value iteration |
forEach | ✅ | ✅ | ❌ | Callbacks, side effects |
for...of + entries() | ✅ | ✅ | ✅ | Index + value cleanly |
Common Loop Patterns with Arrays
Pattern 1: Build a New Array
Loop through one array and build another from it.
let prices = [100, 200, 300, 400, 500];
let discounted = [];
for (let price of prices) {
discounted.push(price * 0.9); // 10% off
}
console.log(discounted); // [90, 180, 270, 360, 450]Pattern 2: Filter Into a New Array
Loop and collect only items that match a condition.
let scores = [45, 82, 60, 91, 73, 55, 88];
let passing = [];
for (let score of scores) {
if (score >= 75) {
passing.push(score);
}
}
console.log(passing); // [82, 91, 88]Pattern 3: Accumulate a Total
Loop and keep a running total.
let cart = [
{ name: "Laptop", price: 55000, qty: 1 },
{ name: "Mouse", price: 800, qty: 2 },
{ name: "Keyboard", price: 1500, qty: 1 },
];
let total = 0;
for (let item of cart) {
total += item.price * item.qty;
}
console.log(`Total: ₹${total.toLocaleString()}`);
// Output: Total: ₹58,100Pattern 4: Find the First Match
Loop and stop as soon as you find what you need.
let students = [
{ name: "Mihir", marks: 92 },
{ name: "Priya", marks: 85 },
{ name: "Rahul", marks: 78 },
];
let topper = null;
for (let student of students) {
if (student.marks > 90) {
topper = student;
break; // Stop — no need to continue
}
}
console.log(topper ? `Topper: ${topper.name}` : "No topper found");
// Output: Topper: MihirPattern 5: Find Max and Min
let scores = [67, 92, 45, 88, 73, 99, 55];
let max = scores[0];
let min = scores[0];
for (let score of scores) {
if (score > max) max = score;
if (score < min) min = score;
}
console.log(`Max: ${max} 🏆`); // Max: 99 🏆
console.log(`Min: ${min} 📉`); // Min: 45 📉Pattern 6: Search and Check Existence
let users = ["Mihir", "Priya", "Rahul", "Sara"];
let target = "Rahul";
let found = false;
for (let i = 0; i < users.length; i++) {
if (users[i] === target) {
console.log(`✅ Found "${target}" at index ${i}`);
found = true;
break;
}
}
if (!found) console.log(`❌ "${target}" not found`);
// Output: ✅ Found "Rahul" at index 2Pattern 7: Transform an Array of Objects
let employees = [
{ name: "Mihir", salary: 50000 },
{ name: "Priya", salary: 45000 },
{ name: "Rahul", salary: 60000 },
];
let withBonus = [];
for (let emp of employees) {
withBonus.push({
name: emp.name,
salary: emp.salary,
bonus: emp.salary * 0.1,
total: emp.salary * 1.1,
});
}
for (let emp of withBonus) {
console.log(`${emp.name.padEnd(8)}: Salary ₹${emp.salary.toLocaleString()} + Bonus ₹${emp.bonus.toLocaleString()} = ₹${emp.total.toLocaleString()}`);
}
// Output:
// Mihir : Salary ₹50,000 + Bonus ₹5,000 = ₹55,000
// Priya : Salary ₹45,000 + Bonus ₹4,500 = ₹49,500
// Rahul : Salary ₹60,000 + Bonus ₹6,000 = ₹66,000Pattern 8: Loop with continue to Skip Items
let orders = [
{ id: 1, status: "delivered", amount: 1500 },
{ id: 2, status: "cancelled", amount: 800 },
{ id: 3, status: "delivered", amount: 2200 },
{ id: 4, status: "pending", amount: 600 },
{ id: 5, status: "delivered", amount: 950 },
];
let deliveredTotal = 0;
for (let order of orders) {
if (order.status !== "delivered") continue;
deliveredTotal += order.amount;
console.log(`✅ Order #${order.id}: ₹${order.amount}`);
}
console.log(`\nDelivered Total: ₹${deliveredTotal.toLocaleString()}`);
// Output:
// ✅ Order #1: ₹1500
// ✅ Order #3: ₹2200
// ✅ Order #5: ₹950
// Delivered Total: ₹4,650Nested Loops with Arrays
Loop Over a 2D Array (Matrix)
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
for (let row of matrix) {
let line = "";
for (let cell of row) {
line += String(cell).padStart(4);
}
console.log(line);
}
// Output:
// 1 2 3
// 4 5 6
// 7 8 9Loop Over Array of Arrays
let schedule = [
["Monday", ["Math", "Science", "English"]],
["Tuesday", ["History", "Art", "PE"]],
["Wednesday", ["Math", "Computer", "Music"]],
];
for (let [day, subjects] of schedule) {
console.log(`\n📅 ${day}:`);
for (let subject of subjects) {
console.log(` • ${subject}`);
}
}
// Output:
// 📅 Monday:
// • Math
// • Science
// • English
// ...Loops vs Array Methods — Which to Use?
Both can solve the same problems. Here's how to decide:
let scores = [85, 92, 78, 60, 95, 55];
// --- TRANSFORM ---
// Loop version
let doubled = [];
for (let s of scores) doubled.push(s * 2);
// Method version — cleaner ✅
let doubled = scores.map(s => s * 2);
// --- FILTER ---
// Loop version
let passing = [];
for (let s of scores) if (s >= 75) passing.push(s);
// Method version — cleaner ✅
let passing = scores.filter(s => s >= 75);
// --- SUM ---
// Loop version
let total = 0;
for (let s of scores) total += s;
// Method version — cleaner ✅
let total = scores.reduce((sum, s) => sum + s, 0);When to use a for / for...of loop:
- Complex multi-step logic per item
- Need to
breakearly (e.g., find first match) - Multiple operations per iteration that don't map cleanly to one method
- Mutating the array elements by index
When to use array methods:
- Single-purpose transformations (
map,filter,reduce) - Chaining multiple operations
- Cleaner, more readable one-liners
Real-World Examples
Example 1: Grade Report Builder
let students = [
{ name: "Mihir", marks: 92, attendance: 95 },
{ name: "Priya", marks: 85, attendance: 80 },
{ name: "Rahul", marks: 55, attendance: 70 },
{ name: "Sara", marks: 78, attendance: 90 },
{ name: "Arjun", marks: 40, attendance: 60 },
];
console.log("=".repeat(55));
console.log(`${"Name".padEnd(10)} | ${"Marks".padEnd(6)} | ${"Att%".padEnd(5)} | Grade | Status`);
console.log("=".repeat(55));
let passed = 0, failed = 0;
for (let s of students) {
let grade = s.marks >= 90 ? "A" : s.marks >= 75 ? "B" : s.marks >= 60 ? "C" : "F";
let status = s.marks >= 40 && s.attendance >= 75 ? "Pass ✅" : "Fail ❌";
status.includes("Pass") ? passed++ : failed++;
console.log(`${s.name.padEnd(10)} | ${String(s.marks).padEnd(6)} | ${String(s.attendance).padEnd(5)} | ${grade} | ${status}`);
}
console.log("=".repeat(55));
console.log(`Results: ${passed} Passed | ${failed} Failed`);Example 2: Product Search Engine
let products = [
{ id: 1, name: "Laptop", category: "Electronics", price: 55000 },
{ id: 2, name: "T-Shirt", category: "Clothing", price: 799 },
{ id: 3, name: "Phone", category: "Electronics", price: 18000 },
{ id: 4, name: "Jeans", category: "Clothing", price: 1499 },
{ id: 5, name: "Earbuds", category: "Electronics", price: 2500 },
{ id: 6, name: "Sneakers", category: "Footwear", price: 3999 },
];
function searchProducts(products, { category = null, maxPrice = Infinity, keyword = "" }) {
let results = [];
for (let product of products) {
let matchCategory = !category || product.category === category;
let matchPrice = product.price <= maxPrice;
let matchKeyword = !keyword || product.name.toLowerCase().includes(keyword.toLowerCase());
if (matchCategory && matchPrice && matchKeyword) {
results.push(product);
}
}
return results;
}
let results = searchProducts(products, { category: "Electronics", maxPrice: 20000 });
console.log(`Found ${results.length} result(s):`);
for (let p of results) {
console.log(` ${p.name.padEnd(12)} ₹${p.price.toLocaleString()}`);
}
// Output:
// Found 2 result(s):
// Phone ₹18,000
// Earbuds ₹2,500Example 3: Word Frequency Counter
let text = "the quick brown fox jumps over the lazy dog the fox";
let words = text.split(" ");
let frequency = {};
for (let word of words) {
frequency[word] = (frequency[word] || 0) + 1;
}
// Sort by frequency and display
let sorted = Object.entries(frequency).sort((a, b) => b[1] - a[1]);
console.log("Word Frequency:");
for (let [word, count] of sorted) {
let bar = "█".repeat(count);
console.log(` ${word.padEnd(8)}: ${bar} (${count})`);
}
// Output:
// Word Frequency:
// the : ███ (3)
// fox : ██ (2)
// quick : █ (1)
// ...Example 4: Batch Data Processor
let transactions = [
{ id: "T001", type: "credit", amount: 5000 },
{ id: "T002", type: "debit", amount: 1200 },
{ id: "T003", type: "credit", amount: 3000 },
{ id: "T004", type: "debit", amount: 800 },
{ id: "T005", type: "credit", amount: 2500 },
{ id: "T006", type: "debit", amount: 4500 },
];
let totalCredit = 0;
let totalDebit = 0;
let balance = 0;
console.log("=== 💳 Transaction History ===");
for (let txn of transactions) {
if (txn.type === "credit") {
totalCredit += txn.amount;
balance += txn.amount;
console.log(`${txn.id} ↑ Credit ₹${txn.amount.toLocaleString().padStart(6)} | Balance: ₹${balance.toLocaleString()}`);
} else {
totalDebit += txn.amount;
balance -= txn.amount;
console.log(`${txn.id} ↓ Debit ₹${txn.amount.toLocaleString().padStart(6)} | Balance: ₹${balance.toLocaleString()}`);
}
}
console.log("─".repeat(50));
console.log(`Total Credit : ₹${totalCredit.toLocaleString()}`);
console.log(`Total Debit : ₹${totalDebit.toLocaleString()}`);
console.log(`Final Balance: ₹${balance.toLocaleString()}`);Common Mistakes
Mistake 1: Modifying an Array While Looping Over It
let items = [1, 2, 3, 4, 5];
// ❌ Pushing inside a for loop — loop never ends!
for (let i = 0; i < items.length; i++) {
items.push(i * 10); // length keeps growing — infinite loop!
}
// ✅ Collect changes, apply after
let toAdd = [];
for (let item of items) {
toAdd.push(item * 10);
}
items.push(...toAdd);Mistake 2: Using forEach and Expecting to break
let numbers = [1, 2, 3, 4, 5];
// ❌ forEach cannot be stopped — break doesn't work!
numbers.forEach(n => {
if (n === 3) break; // SyntaxError!
console.log(n);
});
// ✅ Use for...of when you need break
for (let n of numbers) {
if (n === 3) break; // ✅ Works perfectly
console.log(n);
}
// Output: 1 2Mistake 3: Off-by-One with for Loop
let arr = ["A", "B", "C"]; // length = 3, indexes: 0, 1, 2
// ❌ <= goes one too far — reads undefined
for (let i = 0; i <= arr.length; i++) {
console.log(arr[i]); // A, B, C, undefined ← extra!
}
// ✅ Use <
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]); // A, B, C ✅
}Mistake 4: Returning Inside forEach Doesn't Exit the Outer Function
function findFirst(arr, target) {
arr.forEach(item => {
if (item === target) return item; // ❌ Returns from the callback, NOT findFirst!
});
return null; // Always reaches here
}
// ✅ Use for...of with return
function findFirst(arr, target) {
for (let item of arr) {
if (item === target) return item; // ✅ Returns from findFirst
}
return null;
}
console.log(findFirst(["a", "b", "c"], "b")); // "b" ✅Practical Exercise
Create a file called loops-with-arrays.js:
// 🎯 Loops with Arrays Practice
// 1. Sales report by region
console.log("=== 📊 Regional Sales Report ===");
let sales = [
{ region: "North", rep: "Mihir", amount: 85000 },
{ region: "South", rep: "Priya", amount: 72000 },
{ region: "North", rep: "Rahul", amount: 91000 },
{ region: "East", rep: "Sara", amount: 68000 },
{ region: "South", rep: "Arjun", amount: 79000 },
{ region: "East", rep: "Neha", amount: 55000 },
{ region: "North", rep: "Dev", amount: 63000 },
];
let regionTotals = {};
let topRep = sales[0];
for (let sale of sales) {
regionTotals[sale.region] = (regionTotals[sale.region] || 0) + sale.amount;
if (sale.amount > topRep.amount) topRep = sale;
}
for (let [region, total] of Object.entries(regionTotals)) {
console.log(` ${region.padEnd(8)}: ₹${total.toLocaleString()}`);
}
console.log(`\n🏆 Top Performer: ${topRep.rep} (${topRep.region}) — ₹${topRep.amount.toLocaleString()}`);
// 2. Playlist manager
console.log("\n=== 🎵 Playlist Manager ===");
let playlist = [
{ title: "Blinding Lights", artist: "The Weeknd", duration: 200 },
{ title: "Shape of You", artist: "Ed Sheeran", duration: 234 },
{ title: "Levitating", artist: "Dua Lipa", duration: 203 },
{ title: "Stay", artist: "Kid LAROI", duration: 141 },
{ title: "Peaches", artist: "Justin B.", duration: 198 },
];
let totalDuration = 0;
for (let [i, song] of playlist.entries()) {
let mins = Math.floor(song.duration / 60);
let secs = String(song.duration % 60).padStart(2, "0");
totalDuration += song.duration;
console.log(` ${String(i + 1).padStart(2)}. ${song.title.padEnd(22)} ${song.artist.padEnd(15)} ${mins}:${secs}`);
}
let totalMins = Math.floor(totalDuration / 60);
let totalSecs = String(totalDuration % 60).padStart(2, "0");
console.log(`\n Total duration: ${totalMins}:${totalSecs}`);
// 3. Inventory low-stock alert
console.log("\n=== 📦 Low Stock Alerts ===");
let inventory = [
{ name: "Laptop", stock: 12, minStock: 5 },
{ name: "Mouse", stock: 2, minStock: 10 },
{ name: "Monitor", stock: 8, minStock: 5 },
{ name: "Keyboard", stock: 1, minStock: 10 },
{ name: "Webcam", stock: 20, minStock: 5 },
{ name: "Headset", stock: 3, minStock: 8 },
];
let alerts = [];
for (let item of inventory) {
if (item.stock < item.minStock) {
alerts.push(item);
console.log(` ⚠️ ${item.name.padEnd(12)}: Only ${item.stock} left (min: ${item.minStock})`);
}
}
console.log(alerts.length === 0
? " ✅ All items are sufficiently stocked."
: `\n ${alerts.length} item(s) need restocking.`
);Run it:
node loops-with-arrays.jsExpected Output:
=== 📊 Regional Sales Report ===
North : ₹2,39,000
South : ₹1,51,000
East : ₹1,23,000
🏆 Top Performer: Rahul (North) — ₹91,000
=== 🎵 Playlist Manager ===
1. Blinding Lights The Weeknd 3:20
2. Shape of You Ed Sheeran 3:54
...
Total duration: 16:16
=== 📦 Low Stock Alerts ===
⚠️ Mouse : Only 2 left (min: 10)
⚠️ Keyboard : Only 1 left (min: 10)
⚠️ Headset : Only 3 left (min: 8)
3 item(s) need restocking.Key Takeaways
Congratulations! 🎉 You now know how to combine loops and arrays to solve real-world problems.
✅ 4 ways to loop over arrays — for, for...of, forEach, for...of + entries().
✅ Choose the right loop:
- Need index control or mutation →
for - Just need values →
for...of - Callback style, no
breakneeded →forEach - Both index and value cleanly →
for...of+entries()
✅ 8 key patterns — build, filter, accumulate, find first, max/min, search, transform, skip with continue.
✅ break exits early — for and for...of support it. forEach does not.
✅ continue skips the current iteration — works in for and for...of.
✅ Loops vs methods — use map, filter, reduce for clean single-purpose transformations. Use loops for complex multi-step logic.
✅ Never modify an array while looping over it — collect changes and apply after.
Best Practices
- ✅ Use
for...ofas your default loop for arrays — it's clean and readable - ✅ Use
forwhen you need the index or need to mutate elements directly - ✅ Use
forEachfor side effects — logging, DOM updates — never when you needbreak - ✅ Use
breakto exit early — don't keep iterating after you have your answer - ✅ Use
continueto skip unwanted items — cleaner than deep nesting withif - ✅ Never modify the array while looping — collect changes and apply after
- ✅ Prefer
map,filter,reducefor transformations — loops for complex logic - ✅ Use
return(notbreak) insideforEach— but remember it only exits the callback
What's Next?
Excellent work! 🎉 You now know how to loop over arrays in every possible way and apply real patterns to real data.
Next up, let's explore three of the most powerful array methods in JavaScript in depth:
Map, Filter and Reduce → — transform, select, and compute from arrays like a professional developer!
Let's keep going! 💪