for...of
The for...of loop, introduced in ES2015, walks the values of any iterable object — arrays, strings, Maps, Sets, DOM NodeLists, generators, and more. It reads like plain English, hands you each item directly, and frees you from manual index bookkeeping. For the common case of “do something with every element,” it is the cleanest loop JavaScript offers.
Basic syntax
You declare a variable that receives each value in turn, then name the iterable to loop over:
const colors = ["red", "green", "blue"];
for (const color of colors) {
console.log(color);
}
Output:
red
green
blue
Use const for the loop variable unless you reassign it inside the body — each iteration creates a fresh binding, so closures capture the right value without the var pitfalls of an index loop.
Iterating different iterables
for...of works on anything that implements the iterable protocol, not just arrays. Strings yield their characters (correctly handling multi-byte code points):
for (const char of "café") {
console.log(char);
}
Output:
c
a
f
é
A Set yields its unique values, and a Map yields [key, value] pairs you can destructure inline:
const visits = new Map([
["home", 120],
["about", 30],
]);
for (const [page, count] of visits) {
console.log(`${page} → ${count}`);
}
Output:
home → 120
about → 30
In the browser, DOM collections such as the NodeList returned by document.querySelectorAll are iterable too, so you can loop them directly instead of converting to an array first:
for (const item of document.querySelectorAll("li")) {
item.classList.add("seen");
}
Plain objects (
{ a: 1 }) are not iterable and will throwTypeError: obj is not iterable. Loop their entries withfor (const [k, v] of Object.entries(obj))instead.
Getting the index with entries()
for...of gives you values, not positions. When you also need the index, call the array’s entries() method, which produces [index, value] pairs:
const fruits = ["apple", "banana", "cherry"];
for (const [index, fruit] of fruits.entries()) {
console.log(`${index}: ${fruit}`);
}
Output:
0: apple
1: banana
2: cherry
This keeps the readability of for...of while still exposing the index — no separate counter to declare or increment.
for…of vs for…in
These two look similar but iterate different things. for...of reads values from an iterable; for...in reads enumerable property keys (as strings) from any object, including inherited ones. Confusing them on arrays is a classic bug.
const arr = ["a", "b", "c"];
arr.extra = "oops";
for (const v of arr) console.log(v); // values, skips non-index props
console.log("---");
for (const k in arr) console.log(k); // keys, includes "extra"
Output:
a
b
c
---
0
1
2
extra
| Feature | for...of | for...in |
|---|---|---|
| Iterates | Values | Property keys (strings) |
| Works on | Iterables (arrays, strings, Map, Set…) | Any object |
| Order guaranteed | Yes (iteration order) | Mostly, but don’t rely on it |
| Includes inherited props | No | Yes (enumerable ones) |
| Best for | Arrays and collections | Plain object keys |
The rule of thumb: use for...of for arrays and other collections, and for...in only for inspecting an object’s keys.
Control flow and async
for...of respects break, continue, and return normally — unlike forEach, which cannot be short-circuited:
for (const n of [1, 2, 3, 4, 5]) {
if (n === 4) break;
if (n % 2 === 0) continue;
console.log(n);
}
Output:
1
3
It also pairs cleanly with await: inside an async function, the body can await each iteration in sequence, and the for await...of variant consumes async iterables like streamed data.
async function loadAll(urls) {
for (const url of urls) {
const res = await fetch(url);
console.log(res.status);
}
}
Best Practices
- Reach for
for...ofas the default when you need each value and don’t need the index. - Use
constfor the loop variable unless the body reassigns it. - Call
array.entries()(with destructuring) when you need both index and value. - Never use
for...into iterate array elements — it yields keys and inherited props. - Loop a
MaporSetdirectly; destructureMapentries as[key, value]. - Prefer
for...ofoverforEachwhen you mustbreak,continue, orawaitinside the loop.