JavaScript for of Loop: Complete Guide

The for...of loop is the modern way to iterate over arrays, strings, and other iterable objects in JavaScript. Learn the syntax, when to use it, and how it differs from for...in and forEach.

6 min read

The for...of loop iterates over the values of an iterable object. It works on arrays, strings, Maps, Sets, NodeLists, and any other object that implements the iterable protocol. It was introduced in ES6 and is now the recommended way to loop over array elements when you do not need the index.

Unlike a classic for loop, for...of hides the counter and gives you direct access to each value. Unlike forEach, it supports break, continue, and await.

Basic for...of Syntax

javascriptjavascript
for (const variable of iterable) {
  // use variable
}

The variable is assigned each value from the iterable, one at a time. You can use const because a new binding is created for each iteration.

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

Output:

texttext
apple
banana
cherry

No counter, no index, no .length. Each element is directly available as fruit.

for...of with Strings

Strings are iterable, so for...of gives you each character:

javascriptjavascript
const word = "Hello";
 
for (const char of word) {
  console.log(char);
}

Output:

texttext
H
e
l
l
o

This is cleaner than word[i] in a classic for loop and handles multi-byte characters correctly, including emoji and characters outside the Basic Multilingual Plane.

Getting the Index with entries()

When you need both the index and the value, use .entries():

javascriptjavascript
const colors = ["red", "green", "blue"];
 
for (const [index, color] of colors.entries()) {
  console.log(`${index}: ${color}`);
}

Output:

texttext
0: red
1: green
2: blue

.entries() returns an iterator of [index, value] pairs. Array destructuring in the loop header unpacks each pair into index and color. This gives you the readability of for...of with the index access of a classic for loop.

for...of with Map and Set

for...of works naturally with Map and Set, two iterable collections introduced in ES6:

javascriptjavascript
const scores = new Map([
  ["Alice", 92],
  ["Bob", 85],
  ["Carol", 78],
]);
 
for (const [name, score] of scores) {
  console.log(`${name}: ${score}`);
}
// Alice: 92, Bob: 85, Carol: 78

A Map iterates as [key, value] pairs by default, so destructuring works directly without calling .entries().

javascriptjavascript
const uniqueIds = new Set(["a1", "b2", "c3"]);
 
for (const id of uniqueIds) {
  console.log(id);
}
// a1, b2, c3

A Set iterates over its values one at a time. For more on these, see the Map guide and Set guide.

break and continue in for...of

Unlike forEach, for...of fully supports break and continue:

javascriptjavascript
const numbers = [3, 7, 0, 12, 5];
 
for (const n of numbers) {
  if (n === 0) continue;  // Skip zeros
  if (n > 10) break;      // Stop at large values
  console.log(n);
}
// Prints: 3, 7

This is one of the biggest reasons to choose for...of over forEach. When you need early exit or iteration skipping, forEach cannot help you. For more, see the break statement guide and continue statement guide.

async/await in for...of

forEach does not wait for async operations, but for...of does:

javascriptjavascript
const urls = ["/api/users", "/api/posts", "/api/comments"];
 
for (const url of urls) {
  const response = await fetch(url);
  const data = await response.json();
  console.log(data);
}

Each request completes before the next one starts. This sequential execution is the correct behavior when order matters or when you need to rate-limit API calls. forEach would fire all requests at once and not wait for any of them.

for...of with DOM NodeLists

querySelectorAll returns a NodeList, which is iterable:

javascriptjavascript
const buttons = document.querySelectorAll("button");
 
for (const button of buttons) {
  button.addEventListener("click", () => {
    console.log("Clicked:", button.textContent);
  });
}

This is cleaner than a classic for loop and safer than forEach on older NodeList implementations. Modern browsers support both, but for...of is the more consistent choice across iterables.

What for...of Cannot Do

CannotBecauseAlternative
Iterate plain objectsObjects are not iterablefor...in, Object.keys(), Object.entries()
Modify the original array indexNo index access by defaultClassic for loop or .entries()
Iterate in reverseNo built-in reverse[...arr].reverse() or classic for loop
Skip the first N itemsNo built-in offsetClassic for loop with i = N

For plain objects, see looping through objects in JavaScript. For index-based control, see the classic for loop guide.

for...of vs Other Loops

Featurefor...ofClassic forforEach
Values directlyYesVia indexYes
Index accessVia .entries()Built-in2nd argument
break/continueYesYesNo
await supportYesYesNo
Reverse iterationNoYesNo
Works on objectsNoNoNo

For a detailed side-by-side comparison with tradeoffs, see when to use for, for...of, and forEach.

Rune AI

Rune AI

Key Insights

  • for...of iterates over the values of an iterable, not the keys.
  • Use it on arrays, strings, Maps, Sets, NodeLists, and any iterable.
  • It supports break, continue, and await (unlike forEach).
  • Use .entries() to get both index and value.
  • Plain objects are not iterable; use for...in or Object methods instead.
RunePowered by Rune AI

Frequently Asked Questions

What is the difference between for...of and for...in?

for...of iterates over the values of an iterable (array elements, string characters, Map entries). for...in iterates over the enumerable property keys of an object. Use for...of for arrays and strings, and for...in for plain objects.

Can I use for...of on a plain object?

No. Plain objects are not iterable by default. Trying for...of on an object throws a TypeError. Use for...in, Object.keys(), Object.values(), or Object.entries() to iterate over plain objects.

Does for...of work with async/await?

Yes, and this is one of its biggest advantages over forEach. You can use await directly inside a for...of loop, making it the best choice for sequential async iteration.

Conclusion

The for...of loop is the cleanest, most readable way to iterate over array values in modern JavaScript. It works with any iterable, supports break and continue, and integrates naturally with async/await. If you only need values and want clean syntax, for...of is the right default choice.