for...in vs. for...of in JavaScript

for...in and for...of look similar enough that beginners often use them interchangeably at first. That usually works right up until the loop gives them keys when they expected values, or it starts iterating over an object in a way they did not intend.
The difference is simple once you say it cleanly:
for...initerates over enumerable string keys, including inherited ones; it excludes symbol keysfor...ofiterates over values from an iterable
That one line explains most of the confusion around them.
for...in gives you keys
If you use for...in, the loop variable receives a property key.
With an object, that is often exactly what you want:
const user = {
name: 'Sophie',
role: 'Editor',
};
for (const key in user) {
console.log(key);
}That logs:
namerole
The important point is that the loop gives you the key, not the value.
If you want the value as well, you use the key to access it:
for (const key in user) {
console.log(user[key]);
}for...of gives you values from iterables
for...of is different. It works with iterables such as arrays and gives you the values directly.
const roles = ['Editor', 'Admin', 'Reader'];
for (const role of roles) {
console.log(role);
}That logs the actual array values:
EditorAdminReader
This is why for...of usually feels more natural for arrays. Most of the time, when developers loop an array, they want the values rather than the index keys.
Arrays are Where Beginners Usually Make the Wrong Choice
Using for...in on an array technically works, but it gives you the index keys as strings.
const roles = ['Editor', 'Admin', 'Reader'];
for (const index in roles) {
console.log(index);
}That logs:
012
If you were expecting the role values, that is immediately confusing.
You can still get the values by indexing back into the array:
for (const index in roles) {
console.log(roles[index]);
}but that is exactly why for...of usually reads better for arrays:
for (const role of roles) {
console.log(role);
}Objects and Arrays are Not Symmetrical Here
This is the deeper pattern worth noticing.
For arrays:
for...ofis usually the more natural fit
For plain objects:
for...incan work, because objects have keys rather than iterable values in the same sense
That mismatch is where new developers often stumble. They assume the two loops are just stylistic variations, but in practice they are aimed at different shapes of data.
Why for...of does not work on plain objects by default
Plain objects are not iterable by default.
That means this does not work:
const user = {
name: 'Sophie',
role: 'Editor',
};
for (const value of user) {
console.log(value);
}For an ordinary object, Object.keys() produces an array of its own enumerable string keys. That lets for...of visit each key, which we can use to read the corresponding value:
for (const key of Object.keys(user)) {
console.log(user[key]);
}That is one reason these loops are not interchangeable. for...of depends on iterability, not on the generic idea of "something with properties".
for...in can include inherited keys
This is another reason for...in deserves a bit of caution.
for...in visits enumerable string keys, including inherited ones. Symbol keys are excluded, even when their properties are enumerable.
That means it is not always the best tool when you only want an object's own keys.
In those cases, methods such as Object.keys() are often clearer because they make the boundary more explicit.
This is not a reason to fear for...in, but it is a reason to use it with some understanding rather than treating it as a generic catch‑all loop.
for...of usually communicates intent better for arrays
If you are working with arrays and you want each item, for...of tends to be the more readable choice.
const items = ['bread', 'milk', 'tea'];
for (const item of items) {
console.log(item);
}That reads almost like plain English.
If you need the index as well, then a regular indexed loop or methods such as entries() can become more useful.
Again, the key is not to treat one loop as universally better. It is to match the loop to the data shape and the thing you need from it.
A Quick Side‑by‑Side Example
const colours = ['red', 'green', 'blue'];Using for...in:
for (const index in colours) {
console.log(index); // '0', '1', '2'
}Using for...of:
for (const colour of colours) {
console.log(colour); // 'red', 'green', 'blue'
}That side‑by‑side comparison explains the difference more clearly than any amount of vague advice.
The Best Question to Ask
When choosing between these loops, ask:
"Do I want keys, or do I want values?"
If you want keys, for...in may be appropriate.
If you want values from an iterable, for...of is usually the right fit.
That is a much better decision rule than trying to remember one as "old" and the other as "modern" or anything similarly fuzzy.
Wrapping Up
for...in and for...of differ because they iterate different things. for...in gives you property keys. for...of gives you iterable values. Once that distinction is clear, it becomes much easier to choose the right loop for arrays, objects, and other data structures without getting surprised by the result.
Key Takeaways
for...initerates over enumerable string keys, including inherited ones, but excluding symbols.for...ofiterates over values from iterables.- Arrays usually read more clearly with
for...of. - Plain objects are not iterable by default.
Object.keys()gives us an iterable array of their own enumerable string keys. - Many loop bugs come from choosing a key‑oriented loop when you really wanted values.
Once you focus on whether the loop should yield keys or values, the naming confusion around these two forms becomes much easier to manage.
Postscript
June 2017: ECMAScript 2017 standardised Object.values() and Object.entries(). They provide convenient arrays of values or key‑value pairs for an object's own enumerable string‑keyed properties. The body's Object.keys() alternative keeps the example within the original September 2016 context; the examples use plain JavaScript.