tryjs.app

JavaScript for...of vs for...in — Which to Use and Why

Learn the difference between for...of and for...in loops in JavaScript with runnable examples. When to use each, and why for...in surprises most developers.

for...of vs for...in

Choosing the right iteration syntax

javascriptJS Fundamentals
const arr = ["a", "b", "c"];
arr.custom = "oops"; // simulate pollution

// for...of: values only, ignores custom
for (const value of arr) {
  console.log("of:", value);
}

// for...in: picks up indices AND custom — usually bad
for (const key in arr) {
  console.log("in:", key);
}

// Correct: index + value
for (const [i, v] of arr.entries()) {
  console.log(`${i} -> ${v}`);
}

// Objects: use Object.entries
const user = { name: "Alice", age: 30 };
for (const [key, value] of Object.entries(user)) {
  console.log(`${key}: ${value}`);
}

// Works on strings, Maps, Sets
for (const char of "hi") console.log(char);
for (const val of new Set([1, 2, 3])) console.log(val);

Overview

for...of and for...in look similar but iterate over completely different things. for...of iterates values of any iterable — arrays, strings, Maps, Sets, generators. for...in iterates the enumerable keys of an object, including inherited ones, and is almost never what you want for arrays. Pick for...of for ordered collections and for...in only when you deliberately want every string key of an object (and you probably don't).

How It Works

for...of: values of an iterable

Works on any object with a [Symbol.iterator]() method: arrays, strings, Maps, Sets, NodeLists, generators. Gives you the values in iteration order. The 2015+ idiomatic way to loop.

for...in: enumerable string keys

Iterates over every enumerable string-keyed property of an object, including properties inherited through the prototype chain. Order is roughly insertion order for string keys, but numeric keys come first in ascending order.

Arrays: use for...of, not for...in

for...in on an array iterates indices as strings — and also picks up any added properties or inherited pollution. Always use for...of or forEach for arrays.

Objects: prefer Object.keys/entries + for...of

Instead of for...in, use for (const [key, value] of Object.entries(obj)). This gives you your own enumerable keys only, with their values, in one line.

Common Mistakes

  • Using for...in on arrays — picks up prototype pollution and gives indices as strings.
  • Forgetting that for...in walks the prototype chain; use hasOwnProperty or Object.keys to filter.
  • Reaching for for...of on a plain object — plain objects aren't iterable, you'll get a TypeError.
  • Using for...of when you need the index — use entries(): for (const [i, v] of arr.entries()).

When to Use It

Use for...of for anything iterable (arrays, strings, Maps, Sets, generators). Use for...in only for debugging or when you genuinely need every enumerable string key of an object — and even then, Object.keys/entries is usually clearer.

Frequently Asked Questions

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

for...of iterates values of any iterable (arrays, strings, Maps, Sets). for...in iterates enumerable string keys of an object, including inherited ones. Use for...of for values, Object.keys/entries for object keys.

Can I use for...in with an array?

You can, but you shouldn't. for...in on an array yields indices as strings and also walks any added or inherited properties. Use for...of, forEach, or a classic for-loop instead.

Why is for...of better than forEach?

for...of supports break, continue, and return from an enclosing function; forEach doesn't. for...of also works with await for async iteration. forEach is shorter when you truly want to run a callback on every element and nothing else.

How do I get both the index and value with for...of?

Use .entries(): for (const [i, v] of arr.entries()) { ... }. This gives you both without falling back to a classic for-loop.