Понимание того, как for-of работает за кулисами, чтобы использовать весь его потенциал и перестать делать неверные прогнозы при его использовании.
Отказ от ответственности: это не одна из тех статей, в которых повторяются функции ES6 / ESnext только для того, чтобы вы знали, как они выглядят, но здесь мы подробно рассмотрим, что происходит за кулисами, когда вы используете for-of, как предусмотрено ES6 (ECMASCRIPT 2015)
ES6 предоставляет синтаксис for-of ,, который является довольно удобным способом перебора значений в массиве (в основном) или так называемых итераций - подробнее об этом скоро.
с good-ol для цикла было бы совсем иначе
сравнивая фрагменты i и ii, вы подтверждаете, что for-of выполняет работу более интуитивно, не открывая индекс. Хотя это совершенно гладко и просто, нужно еще кое-что понять. Теперь давайте заглянем за кулисы, чтобы увидеть, как работает for-of.
Фактическое поведение
for-of запрашивает объект-итератор (из внутренней функции по умолчанию, известной как @@ iterator) вещей, которые нужно повторить. , цикл затем перебирает последовательное возвращаемое значение при вызове метода итераторов
.next()
, один раз для каждой итерации цикла
Не беспокойтесь, если вы этого не совсем понимаете!
Такие типы, как Strings, Array, TypedArray, Maps и Set, реализуют метод @@ iterator. Это означает, что объект (или один из объектов в цепочке прототипов) должен иметь свойство с ключом @@ итератора, доступным через константу Symbol.iterator.
Итератор
Итератор - это объект, реализующий .next()
метод. Значение next
- это функция с нулевым аргументом, которая возвращает объект как минимум с двумя свойствами done
и value
.
done
это логическое (_7 _ / _ 8_) значение, которое указывает, должен ли for-of завершать итерацию или нет.
value
- это значение, которое должно возвращаться на каждой итерации функцией for-of..
{ next: function(){ return{value: 10 , done:false} } }
Итерабельный
Как правило, любой объект, реализующий метод @@ iterator, является итерируемым. Следовательно, Строки, Array, TypedArray, Maps и Set являются итеративными. По сути, объект должен иметь свойство с ключом @@ iterator, который реализуется через константу Symbol.iterator
.
Обычный объект по умолчанию не поддерживает итерацию.
const foo = {name: "Agboola Jude", password:"*****"} for(const value of foo){//..} Uncaught TypeError: foo is not iterable
Поскольку for-of принимает итератор, вы получите TypeError
, который будет отброшен на вас, если foo
не является итератором. Обычные объекты не являются итеративными, поэтому вы должны реализовать метод @@ iterator (мы рассмотрим это вскоре), чтобы заставить их работать в цикле for-of и некоторые другие синтаксисы, ожидающие итерабельности , что выходит за рамки этой статьи. Попытайтесь понять это, и вы перестанете использовать их неправильно.
Доступ к методу итератора вручную
Ранее я упоминал, что Strings, Array, TypedArray, Maps и Set реализуют метод @@ iterator . Он реализован по умолчанию для любого из этих типов (для каждого типа совершенно разные реализации).
Теперь позвольте получить доступ к методу итератора для типа String, как обычно делает for-of за кулисами.
Исходя из вышесказанного, я рад сообщить вам, что на самом деле for-of делает за кулисами. Он получает метод объекта и вызывает к нему .next()
.
Примечание. Метод @@ iterator фактически возвращает итератор, обратите внимание на итератор!
Пользовательский метод @@ iterator (создание итерации обычного объекта)
По более сложным причинам, которые мы не будем рассматривать в этой части, обычный объект не является итерируемым по умолчанию, что позволяет использовать его для создания более сложных объектов с указанием способа их итерации. если это действительно мощно!
Во фрагменте iv ниже мы определяем объект и делаем его итеративным, реализуя метод @@ iterator. это делается путем добавления ключа @@ iterator к объекту, который доступен через константу: Symbol.iterator
Давай сделаем это!
В приведенном выше фрагменте iv мы извлекли ключи объекта с помощью Object.keys
, в любое время, когда for-of вызывает следующий вызов, мы извлеките значения, увеличивая индекс ключей. Ваша реализация этого может быть совсем другой. Вам решать, как это реализовать. Вам просто нужно убедиться, что вы возвращаете значение и состояние готовности.
Примечание. Вы можете создать бесконечный цикл, если значение done
итератора всегда ложно.
Код в v выше приведет к бесконечному циклу, если break
statement не было добавлено, поскольку состояние итератора done
всегда равно false
. Это то, чего вам следует остерегаться!
Рассмотрение
Вы можете перебирать объекты с помощью синтаксиса for-of ES6 при условии, что они являются итеративными. for-of ищет встроенный или настраиваемый метод @@ iterator . Строки, Array, TypedArray, Maps и Set по умолчанию являются повторяемыми. По сути, все, что делает for-of, - это найти итератор и вызвать .next()
на нем до done == true.
Спасибо за прочтение! Если вы сочтете это полезным, не забудьте добавить несколько аплодисментов. Я иногда делюсь такими статьями. Вы также можете подписаться на меня в твиттере marvinjudehk.
А сейчас до свидания! 👋