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

> Understand the key differences between JavaScript for...in and for...of loops. Learn when to use each to iterate over object properties or iterable values efficiently.

- Repository: [Lydia Hallie/javascript-questions](https://github.com/lydiahallie/javascript-questions)
- Tags: deep-dive
- Published: 2026-03-04

---

**`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](https://github.com/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`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) file of the [lydiahallie/javascript-questions](https://github.com/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:

```javascript
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:

```javascript
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:

```javascript
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:

```javascript
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:

```javascript
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:

```javascript
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`.