JavaScript loops for while for of complete guide 2026

JavaScript Loops: for, while, for…of, for…in Explained with Examples

JavaScript loops let you execute code repeatedly without writing it out dozens of times. Whether you’re processing arrays, reading API responses, or building game ticks, loops are one of the most fundamental constructs you’ll use daily. This guide covers every loop type in JavaScript — from the classic for loop to the modern for...of — with practical patterns, performance tips, and the gotchas that trip up even experienced developers.

If you haven’t covered JavaScript Conditionals yet, start there — loops and conditionals work hand-in-hand.

Why Loops Matter in JavaScript

Imagine you have an array of 1,000 users and need to send each one a notification. Without loops, you’d need 1,000 lines of nearly identical code. Loops solve this by letting you write the logic once and run it as many times as needed. They’re used everywhere: rendering UI lists, processing form inputs, searching data structures, running animations, and building algorithms.

JavaScript provides several loop types, each suited to different situations. The key is knowing which one to reach for — and when to use array methods instead.

The for Loop

The for loop is the workhorse of JavaScript iteration. It gives you complete control over initialization, condition checking, and incrementing.

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

The three parts inside the parentheses are: initialization (let i = 0), condition (i < 5), and update (i++). All three are optional — omitting the condition creates an infinite loop (you’d use break to exit).

Counting Backwards

for (let i = 10; i >= 0; i--) {
  console.log(i); // 10, 9, 8, ... 0
}

Stepping by More Than One

for (let i = 0; i < 100; i += 10) {
  console.log(i); // 0, 10, 20, ... 90
}

Multiple Variables

for (let i = 0, j = 10; i < j; i++, j--) {
  console.log(i, j); // 0 10, 1 9, 2 8, 3 7, 4 6
}

Iterating Arrays with for

const fruits = ['apple', 'banana', 'cherry'];
for (let i = 0; i < fruits.length; i++) {
  console.log(fruits[i]);
}

For large arrays, cache the length to avoid recalculating it every iteration:

for (let i = 0, len = fruits.length; i < len; i++) {
  console.log(fruits[i]);
}

while and do…while

The while loop checks its condition before each iteration. If the condition is false initially, the body never executes.

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

The do...while loop guarantees the body runs at least once because it checks the condition after each iteration:

let input;
do {
  input = prompt('Enter "yes" to continue:');
} while (input !== 'yes');

This is perfect for menu systems, retry logic, or any situation where you need at least one execution.

When to Use while vs for

Use while when you don’t know how many iterations you need ahead of time — reading from a stream, waiting for a condition, or processing until a queue is empty. Use for when you know the count or are iterating a collection with indices.

for…in — Iterating Object Keys

The for...in loop iterates over the enumerable string properties of an object, including inherited ones:

const user = { name: 'Chirag', role: 'admin', level: 42 };
for (const key in user) {
  console.log(key, user[key]);
}
// name Chirag
// role admin
// level 42

The Prototype Pitfall

function Person(name) { this.name = name; }
Person.prototype.species = 'human';

const p = new Person('Alice');
for (const key in p) {
  console.log(key); // name, species (inherited!)
}

To skip inherited properties, use hasOwnProperty:

for (const key in p) {
  if (p.hasOwnProperty(key)) {
    console.log(key); // name only
  }
}

Or better, use Object.keys(), Object.values(), or Object.entries() which only return own properties.

Never Use for…in on Arrays

While it technically works, for...in on arrays iterates string indices and includes non-numeric properties. The order isn’t guaranteed in older engines. Always use for...of or a standard for loop for arrays.

for…of — Iterating Iterables

Introduced in ES6, for...of iterates over iterable objects: arrays, strings, Maps, Sets, NodeLists, generators, and anything implementing the iterable protocol.

const colors = ['red', 'green', 'blue'];
for (const color of colors) {
  console.log(color); // red, green, blue
}

Strings

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

Maps and Sets

const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
  console.log(key, value); // a 1, b 2
}

const set = new Set([10, 20, 30]);
for (const num of set) {
  console.log(num); // 10, 20, 30
}

Getting the Index with entries()

const fruits = ['apple', 'banana', 'cherry'];
for (const [index, fruit] of fruits.entries()) {
  console.log(index, fruit);
}

NodeLists (DOM)

const paragraphs = document.querySelectorAll('p');
for (const p of paragraphs) {
  p.style.color = 'blue';
}

break and continue

The break statement exits the loop entirely. The continue statement skips to the next iteration.

// Find the first negative number
const nums = [3, 7, -2, 5, -8];
for (const n of nums) {
  if (n < 0) {
    console.log('Found:', n); // Found: -2
    break;
  }
}

// Skip even numbers
for (let i = 0; i < 10; i++) {
  if (i % 2 === 0) continue;
  console.log(i); // 1, 3, 5, 7, 9
}

Labeled Statements

Labels let you break or continue an outer loop from inside a nested loop:

outer: for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 3; j++) {
    if (i === 1 && j === 1) break outer;
    console.log(i, j);
  }
}
// 0 0, 0 1, 0 2, 1 0

Labels are rarely used in modern JavaScript — most developers prefer extracting the logic into a function and using return instead. But they’re useful for algorithm-heavy code like matrix searches.

Nested Loops and Performance

Nested loops multiply complexity. A loop inside a loop on the same data gives you O(n²) time complexity:

// O(n²) — find duplicate pairs
const arr = [1, 2, 3, 2, 4, 1];
for (let i = 0; i < arr.length; i++) {
  for (let j = i + 1; j < arr.length; j++) {
    if (arr[i] === arr[j]) {
      console.log(`Duplicate: ${arr[i]} at ${i} and ${j}`);
    }
  }
}

For large datasets, consider using a Set or Map to reduce to O(n):

// O(n) — find duplicates with Set
const seen = new Set();
for (const num of arr) {
  if (seen.has(num)) console.log('Duplicate:', num);
  seen.add(num);
}

Common Loop Patterns

Accumulator Pattern

const prices = [29.99, 9.99, 49.99, 19.99];
let total = 0;
for (const price of prices) {
  total += price;
}
console.log(total); // 109.96

Search Pattern

function findUser(users, id) {
  for (const user of users) {
    if (user.id === id) return user;
  }
  return null;
}

Filter Pattern

const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evens = [];
for (const n of nums) {
  if (n % 2 === 0) evens.push(n);
}
// evens: [2, 4, 6, 8, 10]

Transformation Pattern

const names = ['alice', 'bob', 'charlie'];
const upper = [];
for (const name of names) {
  upper.push(name.toUpperCase());
}

Flatten Pattern

const nested = [[1, 2], [3, 4], [5, 6]];
const flat = [];
for (const arr of nested) {
  for (const num of arr) {
    flat.push(num);
  }
}
// flat: [1, 2, 3, 4, 5, 6]

Avoiding Infinite Loops

An infinite loop runs forever, freezing your browser tab or crashing Node.js. Common causes:

// Bug: i is never incremented
for (let i = 0; i < 10; ) {
  console.log(i); // infinite!
}

// Bug: condition never becomes false
let x = 10;
while (x > 0) {
  console.log(x);
  x++; // should be x--
}

Prevention tips: always ensure the loop variable moves toward the exit condition, add a safety counter during development, and use for...of when possible since it handles termination automatically.

Loops vs Array Methods

Modern JavaScript offers array methods like forEach, map, filter, and reduce that often replace loops:

// Loop
const doubled = [];
for (const n of [1, 2, 3]) {
  doubled.push(n * 2);
}

// Array method (preferred for transforms)
const doubled2 = [1, 2, 3].map(n => n * 2);

When to use loops over array methods:

  • You need break or continue (forEach doesn’t support them)
  • You’re iterating something that isn’t an array (DOM NodeLists, Maps, generators)
  • You need the index and value from a non-array iterable
  • Performance-critical code (loops can be marginally faster)
  • You’re building complex logic with multiple exit points

Loops with Async/Await

A common trap: forEach doesn’t wait for async callbacks. Use for...of instead:

// WRONG — fires all requests simultaneously
urls.forEach(async (url) => {
  const data = await fetch(url); // doesn't wait!
});

// RIGHT — sequential execution
for (const url of urls) {
  const response = await fetch(url);
  const data = await response.json();
  console.log(data);
}

// PARALLEL — if order doesn't matter
const results = await Promise.all(
  urls.map(url => fetch(url).then(r => r.json()))
);

Best Practices

Use const in for...of and for...in when you don’t reassign the variable. Use let in classic for loops. Never use var — it doesn’t create a new binding per iteration, causing closure bugs. Prefer for...of for arrays and iterables, for...in only for objects (with caution), and standard for when you need index control. Extract complex loop bodies into functions to keep code readable.

Next up: JavaScript Conditionals showed you how to make decisions — now that you can loop, learn how to handle things when they go wrong in our Error Handling guide.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *