JavaScriptBeginner

JavaScript for...of vs for...in: Loop Over Arrays and Objects

Learn when to use for...of and for...in in JavaScript, how they differ for arrays, strings and objects, and avoid the most common looping mistakes.

All JavaScript lessons

What you will learn

In the loops lesson you walked through lists using a counter (i). That works, but it is easy to get wrong. JavaScript has two cleaner loops for this job: for...of, which gives you the values, and for...in, which gives you the keys (names) of an object. In this lesson you will learn how each one works, how they differ, which one to use for arrays, strings and objects, and the mistakes everybody makes at first.

A quick look at arrays and objects

You will study these properly later. For now, you only need to recognise them.

An array is an ordered list of values, written in square brackets. Each value has a number (index), starting from 0:

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

console.log(fruits[0]);        // "apple"
console.log(fruits.length);    // 3

An object is a set of key: value pairs, written in curly braces. You read a value using its key:

const user = { name: "Riya", age: 20, city: "Delhi" };

console.log(user.name);        // "Riya"
console.log(user["age"]);      // 20

In user, the keys are name, age and city. The values are "Riya", 20 and "Delhi".

The old way: a counter loop

To print every fruit, you could write:

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

for (let i = 0; i < fruits.length; i++) {
  console.log(fruits[i]);
}

It works, but you must write the start, the condition and the update, and a small slip (<= instead of <) creates a bug. Often you do not even care about the index. You just want each item.

for...of: loop over values

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

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

Output:

apple
banana
mango

Read it like English: “for each fruit of the fruits, print the fruit.”

for ( const item of collection ) {
  // item is the current value
}
  • item is a variable you name yourself. In every round it holds the next value.
  • There is no counter, no condition and no update. Nothing to get wrong.
  • You can use const, because a new variable is created for each round.

It works on strings too

const word = "hello";

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

Output:

h
e
l
l
o

It even handles emojis correctly, which the counter version cannot:

for (const char of "😀a") {
  console.log(char);   // "😀" then "a"
}

What is “iterable”?

for...of works on anything that is iterable, meaning something that can hand out its values one by one. The common iterables are:

Iterable Example
Arrays [10, 20, 30]
Strings "hello"
Sets new Set([1, 2, 3])
Maps new Map(...)
DOM lists document.querySelectorAll("li")
const unique = new Set([1, 2, 2, 3, 3]);

for (const n of unique) {
  console.log(n);   // 1, 2, 3
}

(You will study Set and Map in their own lesson.)

A plain object is NOT iterable. This is an important point:

const user = { name: "Riya", age: 20 };

// for (const value of user) { }
// TypeError: user is not iterable

For objects, use for...in (next section) or one of the helpers shown later.

Getting the index with for...of

Sometimes you do need the position. Use .entries():

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

for (const [index, fruit] of fruits.entries()) {
  console.log(index, fruit);
}

Output:

0 apple
1 banana
2 mango

The square brackets [index, fruit] are called destructuring. They unpack each pair into two variables. You will learn it in detail later, so for now, just copy this pattern when you need the index.

break and continue work too

const numbers = [4, 8, -2, 10, 6];

for (const n of numbers) {
  if (n < 0) {
    console.log("Found a negative number:", n);
    break;
  }
}
// Skip empty names
const names = ["Riya", "", "Karan", "", "Neha"];

for (const name of names) {
  if (name === "") {
    continue;
  }
  console.log(name);
}

for...in: loop over keys

for...in goes through the keys (property names) of an object:

const user = { name: "Riya", age: 20, city: "Delhi" };

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

Output:

name
age
city

To get the values, use the key to look them up with square brackets:

const user = { name: "Riya", age: 20, city: "Delhi" };

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

Output:

name: Riya
age: 20
city: Delhi

Read it as: “for each key in the user, print the key and its value.”

Why user[key] and not user.key? Dot notation looks for a property literally named key. Square brackets use the value of the variable key, such as "name". Inside a loop you always need the square brackets.

Key order

Keys usually come out in the order they were written, except that whole-number keys come first, in ascending order:

const mixed = { b: 1, 2: "two", a: 2, 1: "one" };

for (const key in mixed) {
  console.log(key);   // "1", "2", "b", "a"
}

Do not use for...in on arrays

It technically works, but it behaves in surprising ways:

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

for (const index in fruits) {
  console.log(typeof index, index);   // "string" "0", then "string" "1"
}
  • The indexes are strings ("0", not 0), so index + 1 gives "01", not 1.
  • It can also include extra properties that someone added to the array, or inherited properties.

Easy rule: for...in is for objects. For arrays and strings, use for...of or a normal for loop.

for...of vs for...in

for...of for...in
Gives you Values Keys (always as strings)
Works on Arrays, strings, Sets, Maps, DOM lists Objects
On a plain object Error (not iterable) Works
On an array Values (use this!) Indexes as text (avoid)

Here is the same array with both loops:

const colors = ["red", "green", "blue"];

for (const color of colors) {
  console.log(color);       // red, green, blue
}

for (const index in colors) {
  console.log(index);       // "0", "1", "2"
}

Memory trick: for ... in gives you the names (the “in” is for index or identifier). for ... of gives you the stuff of the collection, which is the values.

Looping over an object with for...of

Because plain objects are not iterable, JavaScript offers helpers that turn an object into an array, which you can then loop over:

const stock = { apples: 10, bananas: 0, mangoes: 25 };

console.log(Object.keys(stock));     // ["apples", "bananas", "mangoes"]
console.log(Object.values(stock));   // [10, 0, 25]
console.log(Object.entries(stock));  // [["apples", 10], ["bananas", 0], ["mangoes", 25]]

The most useful is Object.entries(), which gives key and value together:

const stock = { apples: 10, bananas: 0, mangoes: 25 };

for (const [item, quantity] of Object.entries(stock)) {
  console.log(`${item}: ${quantity}`);
}

Output:

apples: 10
bananas: 0
mangoes: 25

Many developers prefer this over for...in, because it avoids inherited properties and reads clearly. You will see these helpers in detail in the object-methods lesson.

Real-life use cases

1. Total price of a cart

const prices = [250, 99, 1499, 75];
let total = 0;

for (const price of prices) {
  total += price;
}

console.log(`Total: ₹${total}`);   // "Total: ₹1923"

2. Count how often each letter appears

const text = "banana";
const counts = {};

for (const letter of text) {
  counts[letter] = (counts[letter] || 0) + 1;
}

console.log(counts);   // { b: 1, a: 3, n: 2 }

Each time we see a letter, we add 1 to its count. (counts[letter] || 0) means “use the old count, or 0 if this is the first time”.

3. Find the first number that matches

const marks = [72, 85, 38, 90, 45];

for (const mark of marks) {
  if (mark < 40) {
    console.log("First failing mark:", mark);   // 38
    break;
  }
}

4. Check a form for empty fields

const form = { name: "Riya", email: "", phone: "9876543210" };

for (const field in form) {
  if (form[field].trim() === "") {
    console.log(`${field} is required`);   // "email is required"
  }
}

5. Show an inventory report

const stock = { apples: 10, bananas: 0, mangoes: 25 };

for (const [item, quantity] of Object.entries(stock)) {
  const status = quantity === 0 ? "Out of stock" : `${quantity} left`;
  console.log(`${item}: ${status}`);
}

Output:

apples: 10 left
bananas: Out of stock
mangoes: 25 left

6. Build a URL query string from an object

const filters = { name: "Riya Sharma", city: "Delhi" };
const parts = [];

for (const key in filters) {
  parts.push(`${key}=${encodeURIComponent(filters[key])}`);
}

console.log(parts.join("&"));   // "name=Riya%20Sharma&city=Delhi"

encodeURIComponent() makes the text safe for a URL (the space became %20).

7. Change every item on a web page

The DOM gives you a list of elements, and for...of is perfect for it. With this HTML:

<ul>
  <li>HTML</li>
  <li>CSS</li>
  <li>JavaScript</li>
</ul>

You can update all the list items:

const items = document.querySelectorAll("li");

for (const item of items) {
  item.textContent = item.textContent + " ✔";
}

Every <li> now ends with a tick. (The DOM lessons explain querySelectorAll and textContent in detail.)

What about forEach?

Arrays also have a .forEach() method that does a similar job. You will meet it in the arrays lessons. A key difference is that you cannot use break or continue inside forEach, while you can with for...of. So when you may need to stop early, choose for...of.

Common mistakes

  • Using for...of on a plain object. You get TypeError: ... is not iterable. Use for...in or Object.entries().
  • Using for...in on an array. You get string indexes (and maybe extra properties). Use for...of.
  • Mixing up the two. for (const x in array) gives "0", "1"… and for (const x of object) crashes.
  • Writing obj.key instead of obj[key] inside a for...in. The dot version looks for a property called “key” and gives undefined.
  • Doing maths with for...in keys. They are strings, so "1" + 1 is "11".
  • Expecting an index from for...of. It only gives values. Use .entries() if you need the position.
  • Using const in a classic for counter. for (const i = 0; i < 3; i++) fails. const is fine in for...of and for...in, but not in for (;;).
  • Adding or removing items while looping over the same array. It makes items get skipped. Loop over a copy, or build a new array.
  • Forgetting the keyword before the variable. for (fruit of fruits) creates a global variable by accident. Write for (const fruit of fruits).

Practice

  1. Create an array of 5 of your favourite movies, and print each one with for...of.

  2. Using for...of, print each letter of your name on its own line, in capital letters.

  3. Given const numbers = [3, 8, 1, 9, 4];, calculate their sum and their average with a for...of loop.

  4. Find the largest number in [12, 45, 7, 89, 23] with for...of. Start with let largest = numbers[0];.

  5. Create an object for a book with title, author and price. Print every key and value with for...in.

  6. Print the same book using Object.entries() and for...of. Which version do you find clearer?

  7. Count how many vowels are in the sentence "JavaScript is fun" using for...of.

  8. Predict the output, then run it:

    const scores = [10, 20, 30];
    for (const i in scores) {
      console.log(i + 1);
    }

    Why is the output 01, 11, 21 and not 1, 2, 3? How would you fix it?

  9. Click Practice in Editor and add a second change inside the list loop. For example, make the JavaScript item text uppercase.

  10. Challenge: given const word = "mississippi";, build an object with the count of each letter, then print it with Object.entries().

Recap

  • for...of loops over the values of an iterable: arrays, strings, Sets, Maps and DOM lists. It has no counter, so it is simpler and safer.
  • for...in loops over the keys of an object. Get the value with obj[key]. Keys are always strings.
  • A plain object is not iterable, so for...of fails on it. Use Object.keys(), Object.values() or Object.entries() instead.
  • Do not use for...in on arrays. Use for...of (or for...of with .entries() if you need the index).
  • break and continue work in both loops.
  • Memory trick: in → keys, of → values.
  • Next you will learn functions: how to give a name to a piece of code and reuse it as often as you like.