Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Итерирование не-массивов: iterable и iterator протоколы
В JavaScript не только массивы поддерживают итерирование. Есть специальные протоколы для создания итерируемых объектов и итераторов, которые работают с циклами for...of и spread оператором.
Понятие: Iterator и Iterable
Iterable (итерируемый) — объект, который имеет метод Symbol.iterator, возвращающий итератор.
Iterator (итератор) — объект с методом next(), возвращающий { value, done }.
// Пример встроенного итератора
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
Встроенные итерируемые объекты
Много встроенных объектов в JavaScript уже итерируемы:
// Строки
for (const char of 'hello') {
console.log(char); // h, e, l, l, o
}
// Set
const set = new Set([1, 2, 3]);
for (const value of set) {
console.log(value); // 1, 2, 3
}
// Map
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
console.log(key, value); // a 1, b 2
}
// NodeList (DOM)
const elements = document.querySelectorAll('p');
for (const el of elements) {
console.log(el);
}
// Arguments
function printArgs() {
for (const arg of arguments) {
console.log(arg);
}
}
Создание своего итерируемого объекта
Добавляем метод Symbol.iterator к объекту:
// Собственный объект
const customObject = {
data: [1, 2, 3],
// Делаем объект итерируемым
[Symbol.iterator]() {
let index = 0;
const data = this.data;
return {
next() {
if (index < data.length) {
return {
value: data[index++],
done: false
};
} else {
return { done: true };
}
}
};
}
};
// Теперь можем использовать for...of
for (const value of customObject) {
console.log(value); // 1, 2, 3
}
// И spread оператор
const array = [...customObject]; // [1, 2, 3]
Практический пример: Range (диапазон чисел)
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 { done: true };
}
};
}
}
const range = new Range(1, 5);
for (const num of range) {
console.log(num); // 1, 2, 3, 4, 5
}
const arr = [...range]; // [1, 2, 3, 4, 5]
Generators — синтаксис сахар для итераторов
Geneator функции упрощают создание итераторов. Используй function* и yield:
// Без generator (сложно)
function createIterator(data) {
let index = 0;
return {
next() {
if (index < data.length) {
return { value: data[index++], done: false };
}
return { done: true };
}
};
}
// С generator (просто!)
function* createIterator(data) {
for (const item of data) {
yield item;
}
}
for (const item of createIterator([1, 2, 3])) {
console.log(item);
}
Итерируемый объект с Generator
class IterableCollection {
constructor(data) {
this.data = data;
}
// Делаем класс итерируемым
*[Symbol.iterator]() {
for (const item of this.data) {
yield item;
}
}
}
const collection = new IterableCollection([10, 20, 30]);
for (const item of collection) {
console.log(item); // 10, 20, 30
}
Бесконечный итератор
// Бесконечный счётчик
function* infiniteCounter() {
let count = 0;
while (true) {
yield count++;
}
}
const counter = infiniteCounter();
console.log(counter.next().value); // 0
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2
// С break для остановки
for (const num of infiniteCounter()) {
if (num > 5) break;
console.log(num); // 0, 1, 2, 3, 4, 5
}
Два-стороннее общение: Generator с send()
function* dialogue() {
const greeting = yield 'Привет! Как дела?';
const response = yield `Ты сказал: ${greeting}`;
return `Спасибо за ответ: ${response}`;
}
const gen = dialogue();
console.log(gen.next().value); // 'Привет! Как дела?'
console.log(gen.next('Хорошо').value); // 'Ты сказал: Хорошо'
console.log(gen.next('Пока').value); // 'Спасибо за ответ: Пока'
Пример: Async iterator (загрузка данных)
class DataLoader {
constructor(api) {
this.api = api;
}
async *[Symbol.asyncIterator]() {
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await fetch(`${this.api}?page=${page}`);
const data = await response.json();
for (const item of data.items) {
yield item;
}
hasMore = data.hasMore;
page++;
}
}
}
const loader = new DataLoader('https://api.example.com/items');
for await (const item of loader) {
console.log(item); // Загружает данные по мере итерирования
}
Сравнение способов итерирования
Mетод | Использование | Особенности
------------------
for...of | for (const x of obj) | Требует Symbol.iterator
Object.keys() | for (const k of keys) | Только собственные ключи
Object.entries() | for (const [k,v]...) | Пары ключ-значение
forEach() | obj.forEach(item) | Callback функция
while + iterator | while (!it.done) | Полный контроль
Generator | yield в function* | Простота реализации
async iterator | for await (x of obj) | Асинхронная работа
Вывод: используй Symbol.iterator для создания итерируемых объектов, Generator функции для упрощения кода, и for...of для чистого итерирования.