Такие читатели, как вы, помогают поддерживать MUO. Когда вы совершаете покупку по ссылкам на нашем сайте, мы можем получать партнерскую комиссию. Читать далее.

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

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

Здесь вы познакомитесь с основами и внутренним устройством итератора JavaScript, а также узнаете, как сгенерировать итератор вручную и с помощью генератора.

Итераторы JavaScript

Итератор — это объект JavaScript, реализующий протокол итератора. Эти объекты делают это, имея следующий метод. Этот метод возвращает объект, реализующий ИтераторРезультат интерфейс.

ИтераторРезультат интерфейс содержит два свойства: сделанный и ценить. сделанный свойство является логическим значением, которое возвращает

instagram viewer
ЛОЖЬ если итератор может произвести следующее значение в своей последовательности или истинный если итератор завершил свою последовательность.

ценить Свойство — это значение JavaScript, возвращаемое итератором во время его последовательности. Когда итератор завершает свою последовательность (когда сделанныйистинный), это свойство возвращает неопределенный.

Как следует из названия, итераторы позволяют вам «перебирать» объекты JavaScript, такие как массивы или карты. Такое поведение возможно из-за итерируемого протокола.

В JavaScript итерируемый протокол — это стандартный способ определения объектов, которые вы можете перебирать, например, в для... из петля.

Например:

константа фрукты = ["Банан", "Манго", "Яблоко", "Виноград"];

для (константа итератор из фрукты) {
консоль.log (итератор);
}

/*
Банан
манго
Яблоко
Виноград
*/

В этом примере повторяется фрукты массив с помощью для... из петля. На каждой итерации он записывает текущее значение в консоль. Это возможно, потому что массивы повторяемы.

Некоторые типы JavaScript, такие как массивы, строки, Наборы и карты, являются встроенными итерируемыми объектами, потому что они (или один из объектов в их цепочке прототипов) реализуют @@итератор метод.

Другие типы, такие как Objects, по умолчанию не поддерживают итерацию.

Например:

константа итерОбъект = {
легковые автомобили: ["Тесла", "BMW", "Тойота"],
животные: ["Кот", "Собака", "Хомяк"],
еда: ["Бургеры", "Пицца", "Макаронные изделия"],
};

для (константа итератор из итерОбъект) {
консоль.log (итератор);
}

// TypeError: iterObject не является итерируемым

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

Делаем объект итерируемым

Чтобы сделать объект итерируемым, вы должны реализовать Символ.iterator метод на объекте. Чтобы стать итерируемым, этот метод должен возвращать объект, реализующий ИтераторРезультат интерфейс.

Символ.iterator символ служит той же цели, что и @@итератор и могут использоваться взаимозаменяемо в «спецификации», но не в коде, как @@итератор недопустимый синтаксис JavaScript.

Блоки кода ниже представляют собой пример того, как сделать объект итерируемым с помощью iterObject.

Во-первых, добавьте Символ.iterator способ iterObject с использованием функция декларация.

Вот так:

итерОбъект[Символ.итератор] = функция () {
// Последующие блоки кода идут сюда...
}

Далее вам потребуется получить доступ ко всем ключам в объекте, который вы хотите сделать итерируемым. Вы можете получить доступ к ключам, используя Object.keys метод, который возвращает массив перечисляемых свойств объекта. Чтобы вернуть массив iterObjectключи, передайте этот ключевое слово в качестве аргумента Object.keys.

Например:

позволять objProperties = Объект.ключи(этот)

Доступ к этому массиву позволит вам определить поведение объекта при итерации.

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

Например:

позволять Индекс свойства = 0;
позволять дочерний индекс = 0;

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

Далее вам нужно реализовать и вернуть следующий метод.

Вот так:

возвращаться {
следующий() {
// Последующие блоки кода идут сюда...
}
}

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

Если этот случай не обрабатывается, попытка перебора объекта приведет к бесконечному циклу.

Вот как обработать пограничный случай:

если (индекс свойства > objProperties.длина- 1) {
возвращаться {
ценить: неопределенный,
сделанный: истинный,
};
}

Далее вам потребуется получить доступ к свойствам объектов и их дочерним элементам, используя объявленные ранее переменные-счетчики.

Вот так:

// Доступ к родительским и дочерним свойствам
константа свойства = этот[objProperties[propertyIndex]];

константа свойство = свойства[childIndex];

Далее вам нужно реализовать некоторую логику для увеличения переменных счетчика. Логика должна сбросить дочерний индекс когда в массиве свойства больше нет элементов, и перейти к следующему свойству в объекте. Кроме того, он должен увеличивать дочерний индекс, если в массиве текущего свойства еще есть элементы.

Например:

// Логика увеличения индекса
если (childIndex >= properties.length - 1) {
// если в дочернем массиве больше нет элементов
// перезагрузитьребенокиндекс
дочерний индекс = 0;

// Переходим к следующему свойству
Индекс свойства++;
} еще {
// Переходим к следующему элементу дочернего массива
дочерний индекс++
}

Наконец, верните объект с сделанный свойство установлено на ЛОЖЬ и ценить свойство, установленное для текущего дочернего элемента в итерации.

Например:

возвращаться {
сделанный: ЛОЖЬ,
стоимость: свойство,
};

Ваше завершенное Символ.iterator функция должна быть похожа на блок кода ниже:

итерОбъект[Символ.итератор] = функция () {
константа objProperties = Объект.ключи(этот);
позволять Индекс свойства = 0;
позволять дочерний индекс = 0;

возвращаться {
следующий: () => {
// Обработка пограничного случая
если (индекс свойства > objProperties.длина- 1) {
возвращаться {
ценить: неопределенный,
сделанный: истинный,
};
}

// Доступ к родительским и дочерним свойствам
константа свойства = этот[objProperties[propertyIndex]];

константа свойство = свойства[childIndex];

// Логика увеличения индекса
если (childIndex >= properties.length - 1) {
// если в дочернем массиве больше нет элементов
// перезагрузитьребенокиндекс
дочерний индекс = 0;

// Переходим к следующему свойству
Индекс свойства++;
} еще {
// Переходим к следующему элементу дочернего массива
дочерний индекс++
}

возвращаться {
сделанный: ЛОЖЬ,
стоимость: свойство,
};
},
};
};

Запуск для... из петля на iterObject после этой реализации не будет выдаваться ошибка, так как она реализует Символ.iterator метод.

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

Генераторы JavaScript

Генератор JavaScript — это функция, выполнение которой можно приостановить и возобновить в любой момент. Такое поведение позволяет ему создавать последовательность значений с течением времени.

Функция генератора, которая возвращает генератор, представляет собой альтернативу созданию итераторов.

Вы можете создать функцию-генератор так же, как вы создаете объявление функции в JavaScript. Единственное отличие состоит в том, что вы должны добавить звездочку (*) к ключевому слову функции.

Например:

функция* пример () {
возвращаться"Генератор"
}

Когда вы вызываете обычную функцию в JavaScript, она возвращает значение, заданное ее возвращаться ключевое слово или неопределенный в противном случае. Но функция-генератор не возвращает никакого значения немедленно. Он возвращает объект Generator, который вы можете присвоить переменной.

Чтобы получить доступ к текущему значению итератора, вызовите метод следующий метод объекта Генератор.

Например:

константа ген = пример();

console.log(gen.next()); // { ценить: 'Генератор', сделанный: истинный }

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

Ключевое слово доходности

урожай ключевое слово обеспечивает способ перебора значений в генераторах, приостанавливая выполнение функции генератора и возвращая значение, следующее за ним.

Например:

функция* пример() {
урожай"Модель С"
урожай«Модель Х»
урожай"Кибергрузовик"

возвращаться"Тесла"
}

константа ген = пример();

console.log(gen.next()); // { ценить: «Модель С», сделанный: ЛОЖЬ }

В приведенном выше примере, когда следующий метод вызывается на пример генератор, он будет останавливаться каждый раз, когда встречает урожай ключевое слово. сделанный свойство также будет установлено в ЛОЖЬ пока не встретится с возвращаться ключевое слово.

Вызов следующий метод несколько раз на пример генератор, чтобы продемонстрировать это, в качестве вывода вы получите следующее.

console.log(gen.next()); // { ценить: «Модель Х», сделанный: ЛОЖЬ }
console.log(gen.next()); // { ценить: «Кибергрузовик», сделанный: ЛОЖЬ }
console.log(gen.next()); // { ценить: «Тесла», сделанный: истинный }

консоль.log(gen.следующий()); // { значение: не определено, готово: правда }

Вы также можете перебирать объект Generator с помощью для... из петля.

Например:

для (константа итератор из ген) {
консоль.log (итератор);
}

/*
Модель С
Модель Х
Кибергрузовик
*/

Использование итераторов и генераторов

Хотя итераторы и генераторы могут показаться абстрактными понятиями, это не так. Они могут быть полезны при работе с бесконечными потоками данных и коллекциями данных. Вы также можете использовать их для создания уникальных идентификаторов. Библиотеки управления состоянием, такие как MobX-State-Tree (MST), также используют их «внутри».