Итераторы и итерации
Итераторы привносят концепцию итерации непосредственно в язык javascript и предоставляют механизм для настройки поведения циклов
for...of
/spread operator
.
Итерация -> Итерируемый -> Итератор
Итераторный протокол
Чтобы следовать этому протоколу, объект должен реализовать метод next
, который возвращает object
с ключами value
и done
:
value
: текущий элемент в итерацииdone
: логическое значение, указывающее, завершена ли итерация или нет.
function PersonQuery() { const mike = { first: 'mike', last: 'zheng'}; const pane = { first: 'pane', last: 'huang'}; const john = { first: 'john', last: 'wood'};
let nextPerson = mike; this.next = () => { const currentPerson = nextPerson; switch(currentPerson) { case mike: nextPerson = pane; break; case pane: nextPerson = john; break; default: nextPerson = null; }
const done = currentPerson === null; return { ...(done ? {} : { value: currentPerson }), done } } }
const personIterator = new PersonQuery(); console.log(personIterator.next()); // { "value": { "first": "mike", "last": "zheng" }, "done": false } console.log(personIterator.next()); // { "value": { "first": "pane", "last": "huang" }, "done": false } console.log(personIterator.next()); // { "done": true } console.log(personIterator.next()); // { "done": true }}
Итерируемый протокол
Объект становится итерируемым, если у него есть метод (собственный или унаследованный) с ключом Symbol.iterator
. Этот метод должен возвращать iterator
, объект, который перечисляет элементы «внутри» итерируемого объекта с помощью своего метода next
.
function PersonQuery() {
const mike = { first: 'mike', last: 'zheng'}; const pane = { first: 'pane', last: 'huang'}; const john = { first: 'john', last: 'wood'};
this[Symbol.iterator] = () => { let nextPerson = mike; const next = () => { const currentPerson = nextPerson; switch(currentPerson) { case mike: nextPerson = pane; break; case pane: nextPerson = john; break; default: nextPerson = null; }
const done = currentPerson === null; return { ...(done ? {} : { value: currentPerson }), done } } // conform to iterator protocol return { next }; } }
for (const record of new PersonQuery()) { console.log(record) }
Случаи применения
Оператор отдыха
"Пример"
const [firstPerson, ...rest] = new PersonQuery();
console.log(firstPerson, rest);
Оператор спреда
"Пример"
const numbers1 = [1, 2,3]
const combined = [...numbers1, ...new PersonQuery()];
для… из
"Пример"
"Генератор"
Объект Generator возвращается функцией-генератором и соответствует как протоколу итерации, так и протоколу итератора.
"Пример"
function* PersonQuery() { yield { first: 'mike', last: 'zheng'}; yield { first: 'pane', last: 'huang'}; yield { first: 'john', last: 'wood'}; }
const generatorObject = PersonQuery(); // generatorObject has `next` and [Symbol.iterator] that comform to both iterator and iterable protocol console.log(generatorObject);
// iterator protocol const genObj1 = PersonQuery(); console.log(generatorObject.next()); console.log(generatorObject.next()); console.log(generatorObject.next());
// iterable protocol const genObj2 = PersonQuery(); const iterator = genObj2[Symbol.iterator]() console.log(iterator === genObj2); for(let item of genObj2) { console.log(item); }
Уведомление
- Если вы хотите следить за последними новостями/статьями из серии заметок для чтения, пожалуйста, 「Смотрите」, чтобы подписаться.