Кратко
Секция статьи "Кратко"Итератор — это объект, который умеет обращаться к элементам коллекции по одному за раз, при этом отслеживая своё текущее положение внутри этой последовательности.
Иными словами итератор — это такой механизм, который позволяет перемещаться (итерироваться) по элементам коллекции в определённом порядке и делает их доступными.
Как это понять
Секция статьи "Как это понять"В 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
, который представляет набор данных:
let person = { name: "Mark", age: 30, gender: "male", interests: ["music", "fishing"],}
let 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'] }
Встроенные итераторы
Секция статьи "Встроенные итераторы"В некоторых случаях интерфейс итератора вызывается по умолчанию. Такие объекты как 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.from()" Array
позволяет конвертировать итерируемый объект в 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']
Оператор spread
Секция статьи "Оператор spread"Оператор распространения также вызывает интерфейс итератора по умолчанию:
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
преобразуют итерируемые значения в соответственно 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