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.
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
}
itemis 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 notuser.key? Dot notation looks for a property literally namedkey. Square brackets use the value of the variablekey, 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", not0), soindex + 1gives"01", not1. - It can also include extra properties that someone added to the array, or inherited properties.
Easy rule:
for...inis for objects. For arrays and strings, usefor...ofor a normalforloop.
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...ofon a plain object. You getTypeError: ... is not iterable. Usefor...inorObject.entries(). - Using
for...inon an array. You get string indexes (and maybe extra properties). Usefor...of. - Mixing up the two.
for (const x in array)gives"0","1"… andfor (const x of object)crashes. - Writing
obj.keyinstead ofobj[key]inside afor...in. The dot version looks for a property called “key” and givesundefined. - Doing maths with
for...inkeys. They are strings, so"1" + 1is"11". - Expecting an index from
for...of. It only gives values. Use.entries()if you need the position. - Using
constin a classicforcounter.for (const i = 0; i < 3; i++)fails.constis fine infor...ofandfor...in, but not infor (;;). - 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. Writefor (const fruit of fruits).
Practice
-
Create an array of 5 of your favourite movies, and print each one with
for...of. -
Using
for...of, print each letter of your name on its own line, in capital letters. -
Given
const numbers = [3, 8, 1, 9, 4];, calculate their sum and their average with afor...ofloop. -
Find the largest number in
[12, 45, 7, 89, 23]withfor...of. Start withlet largest = numbers[0];. -
Create an object for a book with
title,authorandprice. Print every key and value withfor...in. -
Print the same book using
Object.entries()andfor...of. Which version do you find clearer? -
Count how many vowels are in the sentence
"JavaScript is fun"usingfor...of. -
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,21and not1,2,3? How would you fix it? -
Click Practice in Editor and add a second change inside the list loop. For example, make the
JavaScriptitem text uppercase. -
Challenge: given
const word = "mississippi";, build an object with the count of each letter, then print it withObject.entries().
Recap
for...ofloops over the values of an iterable: arrays, strings, Sets, Maps and DOM lists. It has no counter, so it is simpler and safer.for...inloops over the keys of an object. Get the value withobj[key]. Keys are always strings.- A plain object is not iterable, so
for...offails on it. UseObject.keys(),Object.values()orObject.entries()instead. - Do not use
for...inon arrays. Usefor...of(orfor...ofwith.entries()if you need the index). breakandcontinuework 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.