for...in vs for...of Loops in JavaScript: Key Differences Explained

for...in iterates over enumerable property keys of an object (including inherited ones), while for...of iterates over values of iterable objects like arrays, strings, and collections.

Understanding the difference between for...in and for...of loops is essential for writing robust JavaScript, as demonstrated in question 79 of the lydiahallie/javascript-questions repository (often referred to as the "myLifeSummedUp" example). While both statements perform iteration, they operate on distinct architectural mechanisms—for...in enumerates property keys whereas for...of consumes the iterator protocol. Choosing the correct loop prevents common bugs when traversing objects, arrays, and other collections.

Core Architectural Differences

for...in Enumerates Property Keys

The for...in statement iterates over all enumerable property keys of an object, including those inherited from the prototype chain. When applied to arrays, it yields the indices as strings (e.g., "0", "1") rather than the actual elements. This loop returns a string key or symbol for each property and must check property descriptors on each iteration, introducing slight overhead on large collections.

for...of Consumes Iterable Values

The for...of statement iterates over values of any object implementing the iterable protocol (possessing a [Symbol.iterator] method). This includes built-in types such as Array, String, Map, Set, NodeList, and generators. Unlike for...in, this loop ignores prototype properties entirely and returns the actual value stored at each position, allowing the JavaScript engine to optimize traversal using internal iterator mechanisms.

Code Examples from the JavaScript Questions Repository

Question 79 in the README.md file of the lydiahallie/javascript-questions repository demonstrates these loops side-by-side in the "myLifeSummedUp" example, illustrating how each loop interacts with different data structures.

Iterating Over Objects with for...in

Use for...in when you need to enumerate the properties of a plain object:

const person = { name: 'Lydia', age: 21 };

for (const key in person) {
  console.log(key, ':', person[key]);
  // Output: name : Lydia
  // Output: age : 21
}

When used on arrays, for...in returns the indices as strings rather than the values:

const arr = ['☕', '💻', '🍷', '🍫'];

for (const idx in arr) {
  console.log(idx); // Output: 0, 1, 2, 3 (as strings)
}

Iterating Over Collections with for...of

Use for...of to access the actual values of iterables:

const arr = ['☕', '💻', '🍷', '🍫'];

for (const item of arr) {
  console.log(item); // Output: ☕ 💻 🍷 🍫
}

// String characters
for (const ch of 'Lydia') {
  console.log(ch); // Output: L y d i a
}

// Set iteration
const set = new Set([1, 2, 3]);
for (const value of set) {
  console.log(value); // Output: 1 2 3
}

Critical Pitfalls and Prototype Chain Behavior

Inherited Properties and hasOwnProperty

Because for...in traverses the entire prototype chain, it can enumerate unexpected properties if they are enumerable:

Array.prototype.customMethod = function() {};

const arr = ['a', 'b'];
for (const key in arr) {
  console.log(key); // Output: 0, 1, customMethod
}

Always filter with hasOwnProperty when using for...in on arrays or objects where prototype pollution is a concern:

for (const key in arr) {
  if (arr.hasOwnProperty(key)) {
    console.log(key); // Output: 0, 1 only
  }
}

Using for...of with Plain Objects

for...of cannot iterate over plain objects because they lack a [Symbol.iterator] method:

const obj = { a: 1, b: 2 };

// TypeError: obj is not iterable
// for (const v of obj) { ... }

// Solution: Convert to iterable first
for (const v of Object.values(obj)) {
  console.log(v); // Output: 1 2
}

Performance Characteristics

The JavaScript engine implements these loops differently. for...of utilizes the internal iterator protocol ([Symbol.iterator]), allowing the engine to optimize traversal of built-in iterables like arrays and strings. This direct value access makes it generally faster for collections.

Conversely, for...in must enumerate property keys and check property descriptors on each iteration, including traversing the prototype chain. This property lookup overhead makes it slower for large arrays and unsuitable for performance-critical iteration over dense data sets.

Summary

  • for...in iterates over enumerable property keys (including inherited ones), returning strings or symbols, and is designed primarily for object property enumeration.
  • for...of iterates over values of iterable objects using the iterator protocol, ignoring prototype properties, and is optimized for arrays, strings, Maps, Sets, and other collections.
  • Always guard for...in with hasOwnProperty when iterating arrays to avoid prototype chain pollution.
  • Use Object.values() with for...of when you need to iterate over the values of a plain object.

Frequently Asked Questions

Can I use for...of on a plain JavaScript object?

No, plain objects do not implement the iterable protocol and lack a [Symbol.iterator] method. Attempting to use for...of on a plain object throws a TypeError. To iterate over object values, use for...in with key access, or convert the object to an iterable using Object.values(obj), Object.keys(obj), or Object.entries(obj) combined with for...of.

Why does for...in return strings instead of numbers for array indices?

Object property keys in JavaScript are fundamentally strings or symbols. When for...in iterates over an array, it treats the array as an object where numeric indices are stored as string property keys (e.g., "0", "1"). This differs from for...of, which accesses the array's internal iterator and yields the actual numeric values stored at those positions.

Is for...of faster than for...in for array iteration?

Generally, yes. for...of utilizes the internal iterator protocol ([Symbol.iterator]) optimized by the JavaScript engine for built-in iterables, allowing direct value access without property lookup overhead. for...in must enumerate property keys, check property descriptors, and traverse the prototype chain on each iteration, making it slower for large arrays and unsuitable for performance-critical code paths.

Should I ever use for...in on arrays?

Generally, no. While for...in technically works on arrays, it iterates over indices as strings and includes enumerable properties from the prototype chain, which often causes unexpected behavior. Prefer for...of for array values, traditional for loops for numeric indices, or Array.prototype.forEach() for functional iteration. Only use for...in on arrays if you specifically need to enumerate indices as strings and have filtered prototype properties using hasOwnProperty.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →