Кратко
СкопированоИтератор — это объект, который умеет обращаться к элементам коллекции по одному за раз, при этом отслеживая своё текущее положение внутри этой последовательности.
Иными словами итератор — механизм, который позволяет перемещаться (итерироваться) по элементам коллекции в определённом порядке и делает их доступными.
Как понять
СкопированоИтератор в JavaScript — объект, возвращающий следующий элемент последовательности через метод next. Этот метод возвращает объект с двумя свойствами:
value— значение текущего элемента коллекции.done— индикатор, указывающий, есть ли ещё в коллекции значения, доступные для перебора.
function makeIterator(array) { let nextIndex = 0 return { next: function () { if (nextIndex < array.length) { const result = { value: array[nextIndex], done: false } nextIndex++ return result } else { return { done: true } } } }}
function makeIterator(array) {
let nextIndex = 0
return {
next: function () {
if (nextIndex < array.length) {
const result = { value: array[nextIndex], done: false }
nextIndex++
return result
} else {
return { done: true }
}
}
}
}
После создания, объект-итератор можно использовать явно с помощью вызова метода next:
let iterator = makeIterator(['Hello', 'world'])console.log(iterator.next().value)// 'Hello'console.log(iterator.next().value)// 'world'console.log(iterator.next().done)// true
let iterator = makeIterator(['Hello', 'world'])
console.log(iterator.next().value)
// 'Hello'
console.log(iterator.next().value)
// 'world'
console.log(iterator.next().done)
// true
Как только метод next завершает перебор, возвращается { done. Это сигнал, что итерирование завершено.
Зачем это нужно
СкопированоПрактически везде, где нужен перебор, его реализуют через итераторы. Это включает в себя не только строки и массивы, но и другие структуры данных. В современный JavaScript добавлена новая концепция «итерируемых» (iterable) объектов, например, Map, представленный в ES6. Это позволяет перебрать итерируемый объект в цикле for:
for (let value of ['a', 'b', 'c']) { console.log(value) // a // b // c}
for (let value of ['a', 'b', 'c']) {
console.log(value)
// a
// b
// c
}
Предположим, у нас есть объект person, который представляет набор данных:
const person = { name: 'Mark', age: 30, gender: 'male', interests: ['music', 'fishing'],}
const person = {
name: 'Mark',
age: 30,
gender: 'male',
interests: ['music', 'fishing'],
}
Чтобы сделать такой объект итерируемым и позволить for работать с ним, определим в нём Symbol:
person[Symbol.iterator] = function () { const properties = Object.keys(this) let count = 0 return { next() { if (count < properties.length) { const key = properties[count] let result = { done: false, value: person[key] } count++ return result } else { return { done: true } } } }}
person[Symbol.iterator] = function () {
const properties = Object.keys(this)
let count = 0
return {
next() {
if (count < properties.length) {
const key = properties[count]
let result = { done: false, value: person[key] }
count++
return result
} else {
return { done: true }
}
}
}
}
Убедимся, что объект person действительно итерируется:
for (let x of person) { console.log(x) // Mark, 30, male, ['music', 'fishing']}
for (let x of person) {
console.log(x)
// Mark, 30, male, ['music', 'fishing']
}
Итератор как глобальный объект
СкопированоНачиная с редакции ECMAScript 2025 Iterator является глобальным объектом. Все встроенные объекты-итераторы наследуются от Iterator.
Проверим, что встроенный итератор Array наследуется от Iterator. Этот код будет правильно работать в Node.js начиная с версии 22:
// Создадим итератор из массиваconst arrayIterator = ['а', 'б'].values()console.log(arrayIterator instanceof Iterator)// true
// Создадим итератор из массива
const arrayIterator = ['а', 'б'].values()
console.log(arrayIterator instanceof Iterator)
// true
Iterator не является обычным классом, потому что не поддерживает создание экземпляров через вызов конструктора с new:
const instance = new Iterator()// TypeError: Abstract class Iterator not directly constructable
const instance = new Iterator()
// TypeError: Abstract class Iterator not directly constructable
Вместо создания экземпляров напрямую, Iterator можно использовать как базовый класс для наследования и доступа к Iterator.
Создадим класс для получения объектов-итераторов:
class PowersOf2 extends Iterator { constructor() { super() this.current = 2 } [Symbol.iterator]() { return this } // Метод возвращает значение степени числа 2 next() { const value = this.current if (value <= 256) { this.current = this.current * 2 return { value, done: false } } return { done: true } }}
class PowersOf2 extends Iterator {
constructor() {
super()
this.current = 2
}
[Symbol.iterator]() {
return this
}
// Метод возвращает значение степени числа 2
next() {
const value = this.current
if (value <= 256) {
this.current = this.current * 2
return { value, done: false }
}
return { done: true }
}
}
Экземпляры класса PowersOf2 будут являться наследниками Iterator:
const iterator = new PowersOf2()console.log(iterator instanceof Iterator)// true
const iterator = new PowersOf2()
console.log(iterator instanceof Iterator)
// true
В ECMAScript 2025 добавлены новые методы доступные через Iterator, упрощающие работу с итераторами как с коллекцией. Например:
to— возвращает массив значений итератора;Array ( ) find— ищет и возвращает первое подходящее значение итератора;( ) some— проверяет значения итератора и возвращает результат выполнения условия.( )
Встроенные итерируемые объекты
СкопированоВ некоторых случаях интерфейс итератора вызывается по умолчанию. Такие объекты, как String, Array, Map и Set итерируемые, потому что их прототипы содержат Symbol.
Где ещё встречается итератор
СкопированоДеструктуризация
СкопированоПри деструктуризации итератор используется для доступа к элементам коллекции:
const [a, b] = new Set(['a', 'b', 'c'])// a// b
const [a, b] = new Set(['a', 'b', 'c'])
// a
// b
Array.from()
СкопированоArray позволяет конвертировать итерируемый объект в массив:
const arr = Array.from(new Set(['a', 'b', 'c']))// ['a', 'b', 'c']
const arr = Array.from(new Set(['a', 'b', 'c']))
// ['a', 'b', 'c']
Спред-оператор
СкопированоСпред-оператор также вызывает интерфейс итератора по умолчанию:
const arr = [...new Set(['a', 'b', 'c'])]// ['a', 'b', 'c']
const arr = [...new Set(['a', 'b', 'c'])]
// ['a', 'b', 'c']
Map, Set
СкопированоКонструкторы Map и Set преобразуют итерируемые значения в Map и Set соответственно:
const map = new Map([ ['uno', 'one'], ['dos', 'two'],])map.get('uno')// onemap.get('dos')// twoconst set = new Set(['red', 'green', 'blue'])set.has('red')// trueset.has('yellow')// false
const map = new Map([
['uno', 'one'],
['dos', 'two'],
])
map.get('uno')
// one
map.get('dos')
// two
const set = new Set(['red', 'green', 'blue'])
set.has('red')
// true
set.has('yellow')
// false
Итератор итератору рознь
СкопированоТермин 'объект-итератор' может использоваться в трёх разных смыслах. Попробуем разобраться.
Перечислим признаки итератора в JS:
- Объект, с методом
next, возвращающий( ) { value— объект, реализующий протокол итератора;, done } - Объект, с методом
Symbol— итерируемый-объект;. iterator ( ) - Объект, имеющий доступ к методам
Iterator— объект-наследник базового объекта. prototype Iterator.
А вот несколько примеров:
- Объект, созданный с помощью функции
makeиз примера в начале статьи, не является итерируемым и не имеет доступа к методамIterator ( ) Iterator.. prototype - Массив или Set-множество не являются итераторами, так как не содержат метода 'next()' и также не имеет доступа к методам
Iterator.. prototype - Встроенный объект-итератор, результат
['a'обладает всеми перечисленными признаками., 'b' , 'c' ] . values ( )
Понимание различий в свойствах объекта поможет избежать ошибок в использовании итераторов.