for...of vs for...in in JavaScript
Javascript is a very interesting language, but on the other end, it can also give you sleepless nights or headaches when you are confused. In your head, your logic is well written, and it should work perfectly, but the JavaScript engine will look at your code and smile 😂😀 (what is this one doing?).
In JavaScript, for...of
and for...in
are two loop constructs that look similar but behave very differently. Many developers, especially beginners, use them interchangeably and end up confused when things don’t work as expected.
Let's look at each of these loop constructs individually before putting them against each other.
Understanding for...in
The for...in
loop is used to iterate over all enumerable properties of an object, including inherited ones.
Basic Syntax:
for (const key in object) {
// access object[key]
}
Example: Looping through a User Profile
You want to display user data on a profile page; you have the userProfile
object:
const userProfile = {
name: "Zainab",
age: 30,
country: "Nigeria"
};
for (const key in userProfile) {
console.log(`${key}: ${userProfile[key]}`);
}
Output:
name: Zainab
age: 30
country: Nigeria
What is happening? Let's go over it together:
On each iteration, key
will hold one of the property names ("name"
, then "age"
, then "country"
). The userProfile[key]
will then fetch the value associated with that key.
This is a great way to dynamically read and display the contents of any object, especially when you don’t know the property names in advance.
Inherited Properties
const base = { country: "Ghana" };
const user = Object.create(base);
user.name = "John";
for (const key in user) {
console.log(key);
}
Output:
name
country
To understand what's going on, let's break down each line. An object is defined called base
that has one property: country: "Ghana"
.
The next line const user = Object.create(base)
is used to create a new object named user
, but it inherits from base
.
At this point, user
itself is empty, but it has access to all properties that exist in the base
object through the prototype chain. That is, user
looks like this:
user = {
__proto__: {
country: "Ghana"
}
}
The last line user.name = "John";
is then used to add a new property name
directly to the user
object. So user
now has:
- An own property:
name
- An inherited property:
country
(frombase
)
The for...in
loop now iterates over all enumerable properties of the user
object, including those inherited through the prototype chain.
If you are hearing about Prototype chain for the first time, don't be scared, in JavaScript it is a mechanism that enables objects to inherit properties and methods from other objects.
Here is the catch: if you only want properties directly on the object, use hasOwnProperty
.
for (const key in user) {
if (user.hasOwnProperty(key)) {
console.log(key);
}
}
Output:
name
This loop is will only iterate over the object’s own properties, not the ones it inherits from its prototype. With this explanation, I am sure you are smiling now 🙂 (nodding in agreement). Let's go over the next one for...of
.
Understanding for...of
The for...of
loop is designed for iterable objects, such as Arrays, Strings, Sets, Maps, and more.
Basic Syntax:
for (const value of iterable) {
// use value directly
}
Example: Displaying Items in a Cart
const cartItems = ["Laptop", "Phone", "Headphones"];
for (const item of cartItems) {
console.log(`Added to cart: ${item}`);
}
Output:
Added to cart: Laptop
Added to cart: Phone
Added to cart: Headphones
You're getting the values directly without any need to access them through their index.
It works on strings too.
for (const char of "Code") {
console.log(char);
}
Output:
C
o
d
e
for...in
vs for...of
Feature | for...in | for...of |
---|---|---|
Iterates over | Enumerable property names (keys) | Iterable values (elements) |
Use with objects? | Yes | No (throws error on plain object) |
Use with arrays? | Yes (returns index, as strings) | Yes (returns actual values) |
Use case | Looping over object properties | Looping through array/string/map/set values |
What You Should Avoid
- Don't use
for...in
on arrays if you only care about the values or order. It can produce unpredictable results when properties are added toArray.prototype
.
Array.prototype.extra = "hello";
const data = ["a", "b"];
for (const i in data) {
console.log(data[i]);
}
Output:
a
b
hello
- Don't use
for...of
on objects directly, unless you make the object iterable.
const obj = { a: 1, b: 2 };
for (const val of obj) {
//Returns - TypeError: obj is not iterable
}
To make it work, convert it:
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
Output:
a: 1
b: 2
Conclusion
When working with objects, go with for...in
. When working with arrays, strings, or anything iterable, go with for...of
. Understanding their difference helps you with the confidence of your program's predictability.