Two Loops, Two Different Jobs
JavaScript has two loop forms that look almost identical but do very different things. for...of walks through the values of an iterable. for...in walks through the keys of an object. One letter of difference, wildly different behavior.
Here's the whole story in one example:
The first loop prints apple, banana, cherry — the values. The second prints 0, 1, 2 — the keys, as strings. Pick the wrong one and you'll spend ten minutes wondering why your array is full of numbers.
for...of: Values From Anything Iterable
for...of is the loop you'll reach for most often. It works on anything JavaScript considers iterable: arrays, strings, Map, Set, NodeList, generators, and more.
No index juggling, no scores[i]. You ask for each value, you get each value. Strings are iterable too — for...of walks them character by character:
That works correctly with most Unicode code points as well, which is a small but real win over indexing into a string by number.
Getting the Index With for...of
The one thing for...of doesn't hand you directly is the position. When you need it, pair the loop with entries():
names.entries() yields [index, value] pairs, and the destructuring on the left splits them into two variables. This is usually cleaner than falling back to a classic for (let i = 0; ...) just because you need i.
for...in: Keys of an Object
for...in is built for plain objects. It iterates over the enumerable string keys:
Note that you get the key, not the value. To read the value, you index back into the object with user[key]. Every key is a string — even if it looks like a number.
for...in also walks up the prototype chain, so it can surface inherited properties. For your own literal objects, that rarely matters, but when looping over instances of a class or objects from a library, it's worth being defensive:
Object.hasOwn(user, key) skips anything inherited. In modern code, most people avoid for...in entirely and use Object.keys, Object.values, or Object.entries instead — which brings us to the next section.
The Modern Way to Loop Over an Object
Rather than for...in, combine for...of with one of the Object.* helpers. You pick which of the three matches what you need:
Object.entries is especially nice — destructuring the [key, value] pair reads like plain English. And because these methods return only the object's own enumerable properties, you don't have to worry about inherited junk.
Don't Use for...in on Arrays
It's technically legal, but it trips people up:
You get 0, 1, 2, and tag. Any property anyone attached to the array — or to Array.prototype via a polyfill — shows up too. The keys are strings, so key + 1 concatenates instead of adding. And the iteration order isn't guaranteed to match the array order in every edge case.
Rule of thumb:
- Array values?
for...of arr. - Array index and value?
for...of arr.entries(). - Array index only, counting? Classic
for (let i = 0; i < arr.length; i++). - Object keys or entries?
Object.keys(obj)/Object.entries(obj)withfor...of.
Basically: for...in is a niche tool. for...of plus the Object helpers covers everything you need.
break and continue Work in Both
Both loops support the usual early-exit tools:
continue skips to the next iteration; break exits the loop entirely. This is the main reason to prefer for...of over .forEach() — forEach callbacks can't break out of the loop, but for...of can.
A Side-by-Side Summary
Four loops, four jobs, one mental model: if you want values from something iterable, use for...of. If you want to work with an object's properties, go through Object.keys / Object.values / Object.entries, also with for...of. Leave for...in for the rare case where you truly want every enumerable string key of an object, inherited or not.
Next: Truthy and Falsy
Every loop and if in JavaScript eventually asks the same question: is this value considered true? That answer isn't always obvious — empty strings, zero, null, and undefined all behave differently than you might expect. Truthy and falsy values are next.
Frequently Asked Questions
What's the difference between for...of and for...in in JavaScript?
for...of iterates over the values of an iterable like an array, string, Map, or Set. for...in iterates over the keys (property names) of an object. For an array ['a', 'b'], for...of gives you 'a' and 'b'; for...in gives you '0' and '1' as strings.
Can I use for...of on an object?
Not directly — plain objects aren't iterable. Use Object.keys(obj), Object.values(obj), or Object.entries(obj) to get an array you can loop over with for...of. for (const [key, value] of Object.entries(obj)) is the common pattern.
Why shouldn't I use for...in on arrays?
It technically works, but for...in walks every enumerable property, including inherited ones and any extras someone added to Array.prototype. It also returns keys as strings, and order isn't fully guaranteed for integer-like keys in every case. Use for...of for values or a classic for loop when you need the index.