Gyaan

Iterators: for...in vs for...of

intermediate iterators for-in for-of loops

JavaScript has two loop constructs that look almost identical but do very different things: for...in and for...of. Mixing them up is a common source of bugs and a popular interview question.

for…in — Iterates over Keys

for...in loops over the enumerable property names (keys) of an object. It gives us strings.

const user = { name: "Manish", age: 25, city: "Pune" };

for (const key in user) {
  console.log(key);        // "name", "age", "city"
  console.log(user[key]);  // "Manish", 25, "Pune"
}

It also walks up the prototype chain, which can give unexpected results:

function Person(name) { this.name = name; }
Person.prototype.species = "Human";

const p = new Person("Manish");

for (const key in p) {
  console.log(key); // "name", then "species" (from prototype!)
}

// To skip inherited properties:
for (const key in p) {
  if (p.hasOwnProperty(key)) {
    console.log(key); // only "name"
  }
}

for…of — Iterates over Values

for...of loops over the values of any iterable — arrays, strings, Maps, Sets, NodeLists, etc.

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

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

const name = "Manish";
for (const char of name) {
  console.log(char); // "M", "a", "n", "i", "s", "h"
}

The Key Difference

The simplest way to remember: in for keys, of for values.

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

for (const x in arr) {
  console.log(x);   // "0", "1", "2" — the indices (keys), as strings!
}

for (const x of arr) {
  console.log(x);   // "a", "b", "c" — the actual values
}

When to Use Which

Use for...in for objects — when we need to loop over an object’s properties:

const config = { theme: "dark", lang: "en", debug: false };
for (const key in config) {
  console.log(`${key} = ${config[key]}`);
}

Use for...of for arrays, strings, Maps, Sets — when we need the values:

const scores = [85, 92, 78, 95];
let total = 0;
for (const score of scores) {
  total += score;
}

Why not use for…in on arrays?

It works, but it’s a bad idea because:

  1. It gives us string indices, not numbers
  2. It iterates over all enumerable properties, not just array elements
  3. The order is not guaranteed (though modern engines do maintain it)
const arr = ["a", "b"];
arr.custom = "oops";

for (const key in arr) {
  console.log(key); // "0", "1", "custom" — includes non-index properties!
}

for (const val of arr) {
  console.log(val); // "a", "b" — only the actual array values
}

for…of and plain objects

Plain objects are not iterable by default, so for...of throws an error:

const user = { name: "Manish" };
// for (const val of user) {} // TypeError: user is not iterable

// Use Object.entries() to make it work:
for (const [key, val] of Object.entries(user)) {
  console.log(`${key}: ${val}`); // "name: Manish"
}

Symbol.iterator (brief mention)

An object is iterable if it has a Symbol.iterator method. Arrays, strings, Maps, and Sets all have it built in. We can make our own objects iterable by defining one, but that’s an advanced topic.

const arr = [1, 2, 3];
console.log(typeof arr[Symbol.iterator]); // "function" — arrays are iterable

const obj = { a: 1 };
console.log(typeof obj[Symbol.iterator]); // "undefined" — plain objects are not

In simple language: for...in gives us keys (and walks up the prototype chain), for...of gives us values (from iterables only). Use for...in for objects, for...of for arrays and other iterables. When in doubt, for...of is usually what you want.