
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 property 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 as keyof typeof user]);}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);}If you want to use for...of with object‑like data, you usually turn the object into an iterable structure first with helpers such as Object.keys, Object.values, or Object.entries.
for (const value of Object.values(user)) { console.log(value);}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 iterates over enumerable keys, including inherited ones if they are part of the chain being exposed that way.
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 keys.for...ofiterates over values from iterables.- Arrays usually read more clearly with
for...of. - Plain objects work more naturally with keys unless you convert them with
Object.keys,Object.values, orObject.entries. - 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.
Related Articles

JSON.parse() and JSON.stringify() Explained for Beginners. 
Object.keys(), Object.values(), and Object.entries() Explained. Object.keys(),Object.values(), andObject.entries()Explained
LeetCode Container with Most Water: The Two‑Pointer Solution. LeetCode Container with Most Water: The Two‑Pointer Solution

Check If Three Values are Equal in JavaScript. Check If Three Values are Equal in JavaScript

Semantic HTML. Semantic HTML

Understanding the :hover Pseudo‑Class in CSS. Understanding the
:hoverPseudo‑Class in CSS
How Inheritance Works in the JavaScript Prototype Chain. How Inheritance Works in the JavaScript Prototype Chain

Automatically Generate urllist.txt from sitemap.xml. Automatically Generate
urllist.txtfromsitemap.xml
React Error Boundaries Explained. React Error Boundaries Explained

Longest Substring Without Repeating Characters in JavaScript. Longest Substring Without Repeating Characters in JavaScript
Handling Click Events in JavaScript. Handling Click Events in JavaScript

Pure Functions in JavaScript. Pure Functions in JavaScript