for...in loops over the keys (property names) of an object.
const user = { name: "Maya", age: 25, city: "Pune" };
for (const key in user) {
console.log(key, "=", user[key]);
}
On each round, key is a string such as "name", and user[key] reads the value.
for…of vs for…in
This is a mix-up almost everyone makes once.
for...of | for...in | |
|---|---|---|
| Gives you | values | keys (as strings) |
| Works on | iterables: arrays, strings, Maps, Sets | objects (and arrays, but see below) |
const letters = ["a", "b", "c"];
for (const item of letters) console.log(item); // a, b, c
for (const key in letters) console.log(key); // "0", "1", "2"
Do not use for…in on arrays
It returns the indexes as strings, and it also visits extra properties that were added to the array, and inherited properties in some situations. For arrays use for...of, a classic for, or array methods.
Inherited properties
for...in also visits enumerable properties from the object’s prototype chain. To be safe, check ownership:
const base = { inherited: true };
const obj = Object.create(base);
obj.own = 1;
for (const key in obj) {
console.log(key, Object.hasOwn(obj, key));
}
The first line prints own true, the second inherited false. You can learn more about prototypes in What Is a Prototype?.
A modern alternative
For plain objects, Object.keys(), Object.values() and Object.entries() give you real arrays that work with for...of and array methods.
for (const [key, value] of Object.entries({ a: 1, b: 2 })) {
console.log(key, value);
}
Most modern code uses Object.entries() and keeps for...in for the rare cases where it needs it.