Введение

На этот раз я собираюсь поговорить об интересной функции javascript, которая, вероятно, не так хорошо известна, но она может помочь нам понять, как работают другие функции.

Кто они такие?

В javascript есть функции для итерации коллекций, например, циклы for, метод map и метод forEach. Итераторы - это еще один способ перебора коллекций, но они позволяют нам настраивать результат итераций. Теперь представьте, что у вас есть объект и вы можете сделать это:

При этом вам необходимо знать, как работают эти протоколы.

Протокол итератора

Протокол итератора определяет стандарт для создания последовательности значений. Этот протокол на самом деле является объектом, который содержит метод next (), который возвращает другой объект с двумя свойствами: значение и готово. Подобно этому итератору, который возвращает счетчик, важно то, что итератор - это объект, который возвращает другой объект с двумя свойствами: значение и выполнено (это просто пример того, как выглядит итератор, если реализовать его с нуля):

Метод next () всегда возвращает объект со свойствами value и done. Свойство value содержит возвращаемое значение, а свойство done указывает на завершение работы итератора. Вы можете вызвать следующий метод в любое время, но в этом примере после третьего вызова вы получите {value: undefined, done: true}. Если вы используете этот код, вам нужно проверить, когда свойство done имеет значение true в вашей логике кода, но вы не будете делать это таким образом, если нужно что-то подобное, лучше использовать Генераторы (об этом напишу позже).

Это была просто наша собственная явная реализация итератора (просто чтобы понять, как он работает), который возвращает простой счетчик. Поскольку у javascript есть простой способ реализовать и написать его, мы собираемся реализовать этот протокол, используя неявный способ позже.

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

Итерируемый протокол позволяет объекту быть итеративным и настраивать его итерационное поведение. Поскольку он является итеративным объектом, ему необходимо реализовать метод @@ iterator (ключ итератора), создавая этот ключ / свойство, вам необходимо реализовать константу Symbol.iterator, этот метод должен возвращать протокол итератора. мы собираемся использовать наш собственный явный протокол итератора.

Возможно, это может немного сбивать с толку, это нормально, как я уже упоминал выше, в javascript есть лучший способ реализовать функцию, которая возвращает итератор, который называется Генератор.

Этот пример более странный, чем предыдущий? ... Позвольте мне объяснить это.

Вы можете увидеть звездочку в операторе функции (функция *), звездочка указывает, что функция является генератором, который возвращает итератор. Другое дело - ключевое слово yield, оно возвращает значение при вызове метода next () и приостанавливает выполнение до next () снова вызывается, возвращая следующий yield. Помните, что генератор возвращает итератор, поэтому, когда эта функция вызывается, не выполняется немедленно, она возвращает протокол итератора (аналогично нашему явному итератору). Этот пример может устранить путаницу (генераторы возвращают дополнительные методы).

Для более глубокого понимания этого кода вам необходимо знать Генераторы в javascript, но это не проблема, если вы этого не знаете. В следующем посте я также расскажу о генераторах. Так как вам нужно знать итераторы, чтобы разбираться в генераторах в деталях. вы также можете проверить MDN.

В чем разница?

Протокол итератора позволяет объекту создавать последовательность значений, которая может использоваться другими выражениями, которые используют это выражение для итерации и отображения значений.

Итерационный протокол указывает, что объект является итеративным, и в нем используется протокол итератора. поэтому вы можете повторить его, используя, например, for… of и оператор распространения ([… obj]).

Связь с оператором for… of и spread

Причина работы for… of и оператора распространения заключается в том, что они внутренне вызывают эти протоколы, проверяя, имеет ли объект итеративный протокол, который указывает, что объект может быть повторен и, следовательно, он содержит протокол итератора для получения своих значений с помощью имеющегося у него метода next ().

Попробуйте сделать этот [… myCustomObject] или for (let p of myCustomObject) {} без реализации протоколов, вы увидите ошибку типа:

TypeError: myCustomObject не повторяется

Встроенные итерируемые объекты

В javascript есть объекты, реализующие эти протоколы, например, Array, String, Set, Map, TypeArray (Int16Array и т. Д.…). По этой причине вы можете использовать для них оператор распространения и для… из.