Кратко
for...of работает не только с массивами — с любым итерируемым объектом. Iterable — объект с методом Symbol.iterator, который возвращает iterator. Iterator имеет метод next(), возвращающий { value, done }.
Подробно
Что такое iterable?
Iterable — объект, который можно перебрать через for...of. Встроенные iterables: Array, String, Map, Set, NodeList.
Что делает for...of? for (const item of iterable) { ... }
Это эквивалентно: const iterator = iterable[Symbol.iterator](); let result = iterator.next(); while (!result.done) { const item = result.value; // ... тело цикла result = iterator.next(); }
Symbol.iterator: Объект — iterable, если у него есть метод [Symbol.iterator], который возвращает iterator.
Iterator: Объект с методом next(), который возвращает { value, done }.
class Range { constructor(start, end) { this.start = start; this.end = end; }
[Symbol.iterator]() { let current = this.start; const end = this.end;
return { next() { if (current <= end) { return { value: current++, done: false }; } return { value: undefined, done: true }; } }; } }
for (const num of new Range(1, 5)) { console.log(num); // 1, 2, 3, 4, 5 }
Ментальная модель
Iterable — как книга. Iterator — как закладка. Вы открываете книгу (Symbol.iterator) и получаете закладку (iterator). Каждый раз, когда вы читаете страницу (next()), закладка двигается вперёд. Когда книга закончится (done: true) — вы останавливаетесь.
Примеры
**Самый простой:**
const arr = [1, 2, 3];
const str = 'abc';
const set = new Set([1, 2, 3]);
const map = new Map([['a', 1], ['b', 2]]);
// Все — iterable:
for (const item of arr) console.log(item);
for (const char of str) console.log(char);
for (const item of set) console.log(item);
for (const [key, val] of map) console.log(key, val);for...of работает с любым iterable.
**Простой:**
// Ручной вызов iterator:
const arr = [10, 20, 30];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // { value: 10, done: false }
console.log(iterator.next()); // { value: 20, done: false }
console.log(iterator.next()); // { value: 30, done: false }
console.log(iterator.next()); // { value: undefined, done: true }Каждый вызов next() возвращает следующее значение.
**Реальный пример:**
class Fibonacci {
constructor(limit) {
this.limit = limit;
}
[Symbol.iterator]() {
let a = 0, b = 1, count = 0;
const limit = this.limit;
return {
next() {
if (count >= limit) return { value: undefined, done: true };
const value = a;
[a, b] = [b, a + b];
count++;
return { value, done: false };
}
};
}
}
for (const num of new Fibonacci(8)) {
console.log(num); // 0, 1, 1, 2, 3, 5, 8, 13
}Кастомный iterable: бесконечная последовательность Фибоначчи с лимитом.
Частые ошибки
**Неправильно:** Путать iterable и iterator
**Почему:** Iterable — объект с Symbol.iterator. Iterator — объект с next(). Разные роли.
**Правильно:** Iterable возвращает iterator. Iterator возвращает значения.
**Неправильно:** Думать, что for...of работает с объектами {}
**Почему:** Обычные объекты НЕ iterable. Только Array, String, Map, Set, NodeList и т.д.
**Правильно:** Для объектов используйте Object.keys/values/entries + for...of.
**Неправильно:** Забывать возвращать { value, done } из next()
**Почему:** next() должен возвращать объект с свойствами value и done.
**Правильно:** return { value: ..., done: true/false }.
Важно запомнить
- Iterable имеет Symbol.iterator, возвращающий iterator
- Iterator имеет next(), возвращающий { value, done }
- for...of = iterable[Symbol.iterator]() + next() цикл
- Обычные {} — НЕ iterable
- Array, String, Map, Set — встроенные iterables
Связь
Назад: Вы знаете Map и Set (JI18) — они тоже итерируемые! Теперь вы знаете, почему.
Вперёд: Вы завершили JS Intermediate! Дальше — JS Async: промисы и async/await.