Понављање преко колекција података коришћењем традиционалних петљи може брзо постати гломазно и споро, посебно када се ради са огромним количинама података.
ЈаваСцрипт Генератори и Итератори пружају решење за ефикасно понављање преко великих колекција података. Користећи их, можете контролисати ток итерације, дати вредности једну по једну и паузирати и наставити процес итерације.
Овде ћете покрити основе и унутрашње карактеристике ЈаваСцрипт итератора и како можете да генеришете итератор ручно и користећи генератор.
ЈаваСцрипт итератори
Итератор је ЈаваСцрипт објекат који имплементира протокол итератора. Ови објекти то чине тако што имају а следећи методом. Овај метод враћа објекат који имплементира ИтераторРесулт интерфејс.
Тхе ИтераторРесулт интерфејс се састоји од два својства: Готово и вредност. Тхе Готово својство је логички број који се враћа
лажно ако итератор може да произведе следећу вредност у свом низу или истина ако је итератор завршио свој низ.Тхе вредност својство је ЈаваСцрипт вредност коју враћа итератор током његовог низа. Када итератор заврши свој низ (када Готовоистина), ово својство се враћа недефинисан.
Као што назив имплицира, итератори вам омогућавају да „итерирате“ преко ЈаваСцрипт објеката као што су низови или мапе. Ово понашање је могуће због итеративног протокола.
У ЈаваСцрипт-у, итерабле протокол је стандардни начин дефинисања објеката преко којих можете итерирати, као што је фор...оф петља.
На пример:
конст воће = ["банана", "манго", "јабука", "Грожђе"];
за (конст итератор оф воће) {
конзола.лог (итератор);
}
/*
Банана
Манго
Аппле
Грожђе
*/
Овај пример понавља воће низ користећи а фор...оф петља. У свакој итерацији бележи тренутну вредност на конзоли. Ово је могуће јер су низови итеративни.
Неки ЈаваСцрипт типови, као што су низови, стрингови, Сетови и мапе, су уграђени итерабле јер они (или један од објеката у ланцу прототипа) имплементирају @@итератор методом.
Други типови, као што су објекти, нису подразумевано итеративни.
На пример:
конст итерОбјецт = {
аутомобили: ["Тесла", "БМВ", "Тојота"],
Животиње: ["мачка", "Пас", "хрчак"],
храна: ["бургери", "Пица", "Тестенина"],
};за (конст итератор оф итерОбјецт) {
конзола.лог (итератор);
}
// ТипеЕррор: итерОбјецт није итерабле
Овај пример показује шта се дешава када покушате да пређете преко објекта који није итерабле.
Прављење објекта итерабле
Да бисте објекат учинили итеративним, морате имплементирати а Симбол.итератор метода на објекту. Да би постао итерабле, овај метод мора да врати објекат који имплементира ИтераторРесулт интерфејс.
Тхе Симбол.итератор симбол служи истој сврси као @@итератор и може се користити наизменично у „спецификацији“, али не и у коду као @@итератор није важећа ЈаваСцрипт синтакса.
Блокови кода у наставку дају пример како направити објекат итеративним коришћењем итерОбјецт.
Прво додајте Симбол.итератор метод да итерОбјецт Користећи функција декларација.
Овако:
итерОбјецт[Симбол.итератор] = функција () {
// Наредни блокови кода иду овде...
}
Затим ћете морати да приступите свим кључевима у објекту који желите да учините итеративним. Можете приступити кључевима помоћу Објекат.кључеви метод, који враћа низ набројивих својстава објекта. Да бисте вратили низ од итерОбјецт'с кључеве, предај ово кључна реч као аргумент за Објекат.кључеви.
На пример:
дозволити објПропертиес = Објекат.кеис(ово)
Приступ овом низу ће вам омогућити да дефинишете итерационо понашање објекта.
Затим, морате да пратите итерације објекта. То можете постићи помоћу променљивих бројача.
На пример:
дозволити пропертиИндек = 0;
дозволити цхилдИндек = 0;
Користићете прву променљиву бројача да бисте пратили својства објекта, а другу да бисте пратили потомке својства.
Затим ћете морати да имплементирате и вратите следећи методом.
Овако:
повратак {
следећи() {
// Наредни блокови кода иду овде...
}
}
Унутар следећи методом, мораћете да обрађујете ивични случај који се јавља када се цео објекат понови. Да бисте руковали ивичним случајем, морате да вратите објекат са вредност подешен на недефинисан и Готово подешен на истина.
Ако се овај случај не обради, покушај итерације преко објекта ће резултирати бесконачном петљом.
Ево како да рукујете ивичним кућиштем:
ако (пропертиИндек > објПропертиес.дужина- 1) {
повратак {
вредност: недефинисан,
Готово: истина,
};
}
Затим ћете морати да приступите својствима објекта и њиховим подређеним елементима користећи променљиве бројача које сте раније декларисали.
Овако:
// Приступ родитељским и подређеним својствима
конст својства = ово[објПропертиес[пропертиИндек]];
конст својство = својства[цхилдИндек];
Следеће, морате да примените неку логику за повећање променљивих бројача. Логика би требало да ресетује цхилдИндек када више нема елемената у низу својства и пређете на следеће својство у објекту. Поред тога, требало би да се повећа цхилдИндек, ако још увек постоје елементи у низу тренутног својства.
На пример:
// Логика повећања индекса
иф (цхилдИндек >= пропертиес.ленгтх - 1) {
// ако у подређеном низу више нема елемената
// ресетоватидетеиндекс
ЦхилдИндек = 0;
// Прелазак на следеће својство
пропертиИндек++;
} друго {
// Прелазак на следећи елемент у подређеном низу
цхилдИндек++
}
На крају, вратите објекат са Готово својство постављено на лажно анд тхе вредност својство постављено на тренутни подређени елемент у итерацији.
На пример:
повратак {
Готово: лажно,
вредност: имовина,
};
Ваш завршен Симбол.итератор функција треба да буде слична блоку кода испод:
итерОбјецт[Симбол.итератор] = функција () {
конст објПропертиес = Објекат.кеис(ово);
дозволити пропертиИндек = 0;
дозволити цхилдИндек = 0;повратак {
следећи: () => {
//Руковање ивичним случајем
ако (пропертиИндек > објПропертиес.дужина- 1) {
повратак {
вредност: недефинисан,
Готово: истина,
};
}// Приступ родитељским и подређеним својствима
конст својства = ово[објПропертиес[пропертиИндек]];
конст својство = својства[цхилдИндек];// Логика повећања индекса
иф (цхилдИндек >= пропертиес.ленгтх - 1) {
// ако у подређеном низу више нема елемената
// ресетоватидетеиндекс
ЦхилдИндек = 0;
// Прелазак на следеће својство
пропертиИндек++;
} друго {
// Прелазак на следећи елемент у подређеном низу
цхилдИндек++
}
повратак {
Готово: лажно,
вредност: имовина,
};
},
};
};
Трчање а фор...оф петља на итерОбјецт након ове имплементације неће избацити грешку јер имплементира а Симбол.итератор методом.
Ручна имплементација итератора, као што смо урадили горе, се не препоручује јер је веома склона грешкама, а логиком може бити тешко управљати.
ЈаваСцрипт Генератори
ЈаваСцрипт генератор је функција коју можете паузирати и наставити са извршавањем у било ком тренутку. Ово понашање му омогућава да произведе низ вредности током времена.
Генераторска функција, која је функција која враћа генератор, пружа алтернативу креирању итератора.
Можете креирати функцију генератора на исти начин на који бисте креирали декларацију функције у ЈаваСцрипт-у. Једина разлика је у томе што морате додати звездицу (*) на кључну реч функције.
На пример:
функција* пример () {
повратак"генератор"
}
Када позовете нормалну функцију у ЈаваСцрипт-у, она враћа вредност коју је одредио њен повратак кључна реч или недефинисан иначе. Али функција генератора не враћа никакву вредност одмах. Враћа објекат Генератор, који можете доделити променљивој.
Да бисте приступили тренутној вредности итератора, позовите следећи метода на објекту Генератор.
На пример:
конст ген = пример();
цонсоле.лог (ген.нект()); // { вредност: 'генератор', Готово: истина }
У горњем примеру, вредност имовина долазила од а повратак кључну реч, ефективно прекидајући генератор. Ово понашање је генерално непожељно са функцијама генератора, јер оно што их разликује од нормалних функција је могућност паузирања и поновног покретања извршења.
Кључна реч приноса
Тхе принос кључна реч обезбеђује начин за понављање вредности у генераторима паузирањем извршавања функције генератора и враћањем вредности која следи.
На пример:
функција* пример() {
принос"Модел С"
принос"Модел Кс"
принос"Сајбер камион"повратак"Тесла"
}конст ген = пример();
цонсоле.лог (ген.нект()); // { вредност: 'Модел С', Готово: лажно }
У горњем примеру, када је следећи метода се позива на пример генератор, паузираће се сваки пут када наиђе на принос кључна реч. Тхе Готово својство ће такође бити подешено на лажно док не наиђе на а повратак кључна реч.
Позивање следећи метода више пута на пример генератор да то демонстрира, имаћете следеће као излаз.
цонсоле.лог (ген.нект()); // { вредност: 'Модел Кс', Готово: лажно }
цонсоле.лог (ген.нект()); // { вредност: 'Сајбер камион', Готово: лажно }
цонсоле.лог (ген.нект()); // { вредност: 'Тесла', Готово: истина }
конзола.лог (ген.нект()); // { валуе: ундефинед, доне: труе }
Такође можете итерирати преко објекта Генератор користећи фор...оф петља.
На пример:
за (конст итератор оф ген) {
конзола.лог (итератор);
}
/*
Модел С
Модел Кс
Цибер Труцк
*/
Коришћење итератора и генератора
Иако итератори и генератори могу изгледати као апстрактни концепти, нису. Они могу бити од помоћи када радите са бесконачним токовима података и збиркама података. Можете их користити и за креирање јединствених идентификатора. Библиотеке за управљање државом као што је МобКс-Стате-Трее (МСТ) такође их користе испод хаубе.