Есть ли связь между for…of и iterable?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Связь между for…of и iterable протоколом
Да, есть прямая и неразрывная связь. for...of цикл работает ТОЛЬКО с объектами, которые реализуют Iterable протокол. Это ключевая концепция в современном JavaScript.
Что такое Iterable протокол
Iterable — это соглашение (протокол) в JavaScript, которое позволяет объекту быть используемым в циклах типа for...of. Объект является iterable, если он имеет метод Symbol.iterator, который возвращает iterator.
// Объект iterable должен иметь Symbol.iterator
const myIterable = {
[Symbol.iterator]() {
// returns iterator object
}
};
Что такое Iterator
Iterator — это объект с методом next(), который возвращает объект с двумя свойствами:
- value — текущее значение
- done — логический флаг (true когда итерация завершена)
const iterator = {
next() {
return { value: someValue, done: false }; // или { done: true }
}
};
Полный пример: создание своего Iterable
// Создаём iterable объект
const countUp = {
[Symbol.iterator]() {
let count = 0;
const max = 3;
return {
next() {
if (count < max) {
return { value: ++count, done: false };
} else {
return { done: true };
}
}
};
}
};
// Используем for...of
for (const num of countUp) {
console.log(num); // 1, 2, 3
}
Встроенные Iterable в JavaScript
1. Строки (Strings):
for (const char of 'hello') {
console.log(char); // h, e, l, l, o
}
2. Массивы (Arrays):
const arr = [1, 2, 3];
for (const item of arr) {
console.log(item); // 1, 2, 3
}
3. Set:
const set = new Set([1, 2, 3]);
for (const item of set) {
console.log(item); // 1, 2, 3
}
4. Map:
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
console.log(`${key}: ${value}`); // a: 1, b: 2
}
5. NodeList (в браузере):
const elements = document.querySelectorAll('div');
for (const el of elements) {
console.log(el); // каждый div
}
Как работает for…of внутри
Когда ты используешь for...of, JavaScript выполняет следующие шаги:
for (const item of iterable) {
// loop body
}
// Эквивалентно:
const iterator = iterable[Symbol.iterator]();
let result = iterator.next();
while (!result.done) {
const item = result.value;
// loop body
result = iterator.next();
}
Практический пример: Iterable для диапазона чисел
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 };
} else {
return { done: true };
}
}
};
}
}
// Использование
const range = new Range(1, 5);
for (const num of range) {
console.log(num); // 1, 2, 3, 4, 5
}
Пример: Iterable для объекта
const user = {
name: 'Alice',
age: 30,
email: 'alice@example.com',
// Делаем объект iterable
[Symbol.iterator]() {
const keys = Object.keys(this);
let index = 0;
return {
next: () => {
if (index < keys.length) {
const key = keys[index++];
return {
value: `${key}: ${this[key]}`,
done: false
};
}
return { done: true };
}
};
}
};
for (const info of user) {
console.log(info);
// name: Alice
// age: 30
// email: alice@example.com
}
Генераторы (Generators) — удобный способ создавать Iterables
Генераторы — это функции, которые автоматически создают Iterable:
function* countUp(max) {
let count = 0;
while (count < max) {
yield ++count; // yield возвращает значение и паузирует функцию
}
}
for (const num of countUp(3)) {
console.log(num); // 1, 2, 3
}
Генератор для диапазона (более простой вариант):
function* range(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
for (const num of range(1, 5)) {
console.log(num); // 1, 2, 3, 4, 5
}
Spread оператор с Iterables
Spread оператор ... также использует Iterable протокол:
const arr = [1, 2, 3];
const copy = [...arr]; // [1, 2, 3]
const str = 'hello';
const chars = [...str]; // ['h', 'e', 'l', 'l', 'o']
const set = new Set([1, 2, 3]);
const arr2 = [...set]; // [1, 2, 3]
Деструктуризация с Iterables
const [first, second] = [1, 2, 3]; // first = 1, second = 2
const [a, b, ...rest] = 'hello'; // a = 'h', b = 'e', rest = ['l', 'l', 'o']
Что НЕ является Iterable
const plainObject = { a: 1, b: 2 };
// ❌ Ошибка: objects are not iterable
for (const item of plainObject) {
console.log(item);
}
// ✅ Для итерации по объектам используй Object.entries()
for (const [key, value] of Object.entries(plainObject)) {
console.log(`${key}: ${value}`);
}
Таблица: Iterable vs Iterator
| Концепция | Описание | Пример |
|---|---|---|
| Iterable | Объект с методом Symbol.iterator | Array, String, Set, Map |
| Iterator | Объект с методом next() | результат Symbol.iterator() |
| for...of | Цикл, использующий Iterable | for (const x of arr) |
Заключение
Связь: for...of работает ИСКЛЮЧИТЕЛЬНО с объектами, которые реализуют Iterable протокол (имеют метод Symbol.iterator). Если объект не iterable, цикл for...of выбросит ошибку TypeError. Это фундаментальный протокол в JavaScript, который позволяет единообразно итерировать различные типы коллекций.