JavaScript for...of vs for...in: Differences and Use Cases

JavaScript has two loop forms that look similar but solve different problems: for...of and for...in. This article explains what each loop does, how they behave on arrays, objects, strings, and other iterable values, and how to choose the right one without getting subtle bugs.

Quick answer: Use for...of to loop over values in an iterable such as an array, string, set, or map. Use for...in to loop over enumerable property names on an object, especially when you need keys rather than values.

Difficulty: Beginner

You'll understand this better if you know: basic JavaScript variables, arrays and objects, and how for loops work at a simple level.

1. What Are for...of and for...in?

for...of and for...in are both loop statements, but they iterate over different things.

In practice, beginners often mix them up because both use the same loop shape. The important difference is what each loop returns to you.

2. Why This Comparison Matters

Choosing the wrong loop can lead to confusing output, accidental traversal of inherited properties, or code that works in one case but fails in another.

for...of is usually the better choice for arrays because it is simpler and reads like “give me each item.” for...in is useful when you need object keys, but it is not a general-purpose array loop.

Knowing the difference also helps you avoid common mistakes such as looping over array indexes when you wanted values, or trying to use for...of on a plain object.

3. Basic Syntax or Core Idea

for...of syntax

for...of reads values from an iterable one at a time. The loop variable receives the current value directly.

const numbers = [10, 20, 30];

for (const number of numbers) {
  console.log(number);
}

Here, number is each array value: 10, then 20, then 30.

for...in syntax

for...in loops over property names. On arrays, those property names are usually indexes written as strings.

const user = {
  name: "Ava",
  role: "admin"
};

for (const key in user) {
  console.log(key, user[key]);
}

Here, key becomes name and role, not the values Ava and admin.

4. Step-by-Step Examples

Example 1: Looping over an array with for...of

When you want the items in an array, for...of is usually the cleanest option.

const fruits = ["apple", "banana", "cherry"];

for (const fruit of fruits) {
  console.log(fruit);
}

This prints each fruit value directly. You do not need to manually access indexes.

Example 2: Looping over array indexes with for...in

for...in can loop over array indexes, but that is usually not the best choice unless you need the index as a property name.

const fruits = ["apple", "banana", "cherry"];

for (const index in fruits) {
  console.log(index, fruits[index]);
}

This works, but the loop variable is a string index like "0", not the value itself. For arrays, for...of is usually easier to read.

Example 3: Looping over object properties with for...in

Plain objects do not implement iteration in the same way arrays do, so for...in is a natural fit when you need keys.

const profile = {
  name: "Mina",
  country: "Canada",
  active: true
};

for (const key in profile) {
  console.log(key + ":", profile[key]);
}

This is useful for printing key-value pairs, validating object fields, or building summaries.

Example 4: Looping over a string with for...of

Strings are iterable, so for...of can read each character directly.

const word = "code";

for (const character of word) {
  console.log(character);
}

This prints c, o, d, and e. The same loop is much less natural with for...in because you would get string indexes instead of letters.

5. Practical Use Cases

6. Common Mistakes

Mistake 1: Using for...of on a plain object

for...of only works on iterable values. A plain object is not iterable by default, so the loop fails.

Problem: This code tries to iterate over an object with for...of, which causes a TypeError: object is not iterable.

const user = { name: "Ava", role: "admin" };

for (const entry of user) {
  console.log(entry);
}

Fix: Use for...in for keys, or convert the object to an array with Object.entries() if you want key-value pairs.

const user = { name: "Ava", role: "admin" };

for (const key in user) {
  console.log(key, user[key]);
}

for (const [key, value] of Object.entries(user)) {
  console.log(key, value);
}

The corrected version works because the loop matches the data structure being used.

Mistake 2: Expecting for...in to give array values

Many beginners use for...in on arrays and then wonder why they get indexes instead of the items themselves.

Problem: This code logs array indexes like 0 and 1, not the actual values.

const numbers = [5, 10, 15];

for (const item in numbers) {
  console.log(item);
}

Fix: Use for...of when you need the array values.

const numbers = [5, 10, 15];

for (const item of numbers) {
  console.log(item);
}

The fixed version is clearer and avoids treating array indexes like data values.

Mistake 3: Forgetting that for...in can see inherited properties

for...in walks enumerable properties, including ones inherited through the prototype chain. That can be surprising if you only want an object’s own properties.

Problem: This code may print inherited properties if they are enumerable, which can produce unexpected output or duplicate work.

const base = { shared: "yes" };
const child = Object.create(base);
child.own = "value";

for (const key in child) {
  console.log(key);
}

Fix: Filter with Object.hasOwn() when you only want properties that belong directly to the object.

const base = { shared: "yes" };
const child = Object.create(base);
child.own = "value";

for (const key in child) {
  if (Object.hasOwn(child, key)) {
    console.log(key);
  }
}

The corrected version avoids accidental traversal of inherited properties.

7. Best Practices

Prefer for...of for arrays and other iterables

When you want values, for...of is easier to read and less error-prone than looping by index or using for...in.

const names = ["Lia", "Noah", "Omar"];

for (const name of names) {
  console.log(name);
}

This style directly communicates that the loop is about values, not indexes.

Use for...in only when you actually need keys

If you need to inspect property names or build a dynamic lookup, for...in is appropriate. Otherwise, consider Object.keys() or Object.entries() for clearer intent.

const settings = { theme: "dark", fontSize: 16 };

for (const key in settings) {
  if (Object.hasOwn(settings, key)) {
    console.log(key, settings[key]);
  }
}

Adding the ownership check keeps the loop focused on the object’s own data.

Remember that array indexes from for...in are strings

If you use for...in on an array, the loop variable is a string key. That can matter when you compare or format values.

const letters = ["a", "b", "c"];

for (const index in letters) {
  console.log(Number(index) + 1, letters[index]);
}

This makes the string nature of the index explicit, but for arrays you still usually want for...of instead.

8. Limitations and Edge Cases

9. Practical Mini Project

Here is a small utility that prints a summary of a grocery list object and its items. It uses for...in for object keys and for...of for array values.

const shoppingList = {
  fruits: ["apple", "banana"],
  vegetables: ["carrot", "spinach"],
  drinks: ["water", "tea"]
};

for (const category in shoppingList) {
  if (Object.hasOwn(shoppingList, category)) {
    console.log(category + ":");

    for (const item of shoppingList[category]) {
      console.log("- " + item);
    }
  }
}

This example shows the practical division of labor: for...in identifies which category keys exist, and for...of processes the items inside each category.

10. Key Points

11. Practice Exercise

Try this small exercise to make the difference stick.

Expected output: You should see each city name on its own line, followed by each object key and its corresponding value.

Hint: Remember that for...of gives values directly, while for...in gives keys that you can use to access values.

Solution:

const cities = ["Paris", "Tokyo", "Lima"];
const person = {
  firstName: "Sam",
  lastName: "Lee",
  age: 29
};

for (const city of cities) {
  console.log(city);
}

for (const key in person) {
  if (Object.hasOwn(person, key)) {
    console.log(key + ":", person[key]);
  }
}

This solution works because each loop matches the structure it is meant to handle.

12. Final Summary

for...of and for...in are easy to confuse, but they answer different questions. for...of asks, “What are the values in this iterable?” while for...in asks, “What enumerable keys does this object have?”

For most array and string work, reach for for...of. For object-key inspection, use for...in carefully and remember to guard against inherited properties when necessary.

If you want to go further, next learn Object.keys(), Object.entries(), and how iterators make for...of possible.