Итераторы и итерации

Итераторы привносят концепцию итерации непосредственно в язык javascript и предоставляют механизм для настройки поведения циклов for...of/spread operator.

Итерация -> Итерируемый -> Итератор

Итераторный протокол

Чтобы следовать этому протоколу, объект должен реализовать метод next, который возвращает object с ключами value и done:

  • value: текущий элемент в итерации
  • done: логическое значение, указывающее, завершена ли итерация или нет.

E.g.

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.

E.g

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);
}

Уведомление

  • Если вы хотите следить за последними новостями/статьями из серии заметок для чтения, пожалуйста, 「Смотрите」, чтобы подписаться.