Iterace shromažďování dat pomocí tradičních smyček se může rychle stát těžkopádným a pomalým, zejména při práci s velkým množstvím dat.
Generátory a iterátory JavaScriptu poskytují řešení pro efektivní iteraci velkých kolekcí dat. Pomocí nich můžete řídit tok iterace, získávat hodnoty jednu po druhé a pozastavit a obnovit proces iterace.
Zde pokryjete základy a vnitřnosti iterátoru JavaScriptu a jak můžete vygenerovat iterátor ručně a pomocí generátoru.
Iterátory JavaScriptu
Iterátor je objekt JavaScriptu, který implementuje protokol iterátoru. Tyto objekty to dělají tím, že mají a další metoda. Tato metoda vrací objekt, který implementuje IteratorResult rozhraní.
The IteratorResult rozhraní obsahuje dvě vlastnosti: Hotovo a hodnota. The Hotovo vlastnost je logická hodnota, která se vrací Nepravdivé pokud iterátor dokáže vytvořit další hodnotu ve své sekvenci nebo skutečný pokud iterátor dokončil svou sekvenci.
The hodnota vlastnost je hodnota JavaScriptu vrácená iterátorem během jeho sekvence. Když iterátor dokončí svou sekvenci (když Hotovoskutečný), tato vlastnost se vrací nedefinováno.
Jak název napovídá, iterátory vám umožňují „iterovat“ objekty JavaScriptu, jako jsou pole nebo mapy. Toto chování je možné díky iterovatelnému protokolu.
V JavaScriptu je iterovatelný protokol standardním způsobem definování objektů, které můžete iterovat, např. pro...z smyčka.
Například:
konst ovoce = ["Banán", "Mango", "Jablko", "Hrozny"];
pro (konst iterátor z ovoce) {
řídicí panel.log (iterátor);
}
/*
Banán
Mango
Jablko
Hrozny
*/
Tento příklad iteruje přes ovoce pole pomocí a pro...z smyčka. V každé iteraci zaznamenává aktuální hodnotu do konzole. To je možné, protože pole jsou iterovatelná.
Některé typy JavaScriptu, jako jsou pole, řetězce, Sady a mapy, jsou vestavěné iterovatelné, protože oni (nebo jeden z objektů v jejich prototypovém řetězci) implementují @@iterátor metoda.
Jiné typy, jako jsou objekty, nelze ve výchozím nastavení iterovat.
Například:
konst iterObject = {
auta: ["Tesla", "BMW", "Toyota"],
zvířat: ["Kočka", "Pes", "Křeček"],
jídlo: ["burgery", "Pizza", "Těstoviny"],
};pro (konst iterátor z iterObject) {
řídicí panel.log (iterátor);
}
// TypeError: iterObject nelze iterovat
Tento příklad ukazuje, co se stane, když se pokusíte iterovat objekt, který nelze iterovat.
Vytvoření iterovatelného objektu
Aby byl objekt iterovatelný, musíte implementovat a Symbol.iterátor metoda na objektu. Aby se tato metoda stala iterovatelnou, musí vrátit objekt, který implementuje IteratorResult rozhraní.
The Symbol.iterátor symbol slouží ke stejnému účelu jako @@iterátor a lze je zaměnitelně použít ve „specifikaci“, ale ne v kódu jako @@iterátor není platná syntaxe JavaScriptu.
Níže uvedené bloky kódu poskytují příklad, jak zajistit, aby byl objekt iterovatelný pomocí iterObject.
Nejprve přidejte Symbol.iterátor metoda k iterObject použitím funkci prohlášení.
Jako tak:
iterObject[Symbol.iterator] = funkce () {
// Následné bloky kódu jdou sem...
}
Dále budete potřebovat přístup ke všem klíčům v objektu, který chcete, aby bylo možné iterovat. Ke klávesám se dostanete pomocí Object.keys metoda, která vrací pole vyčíslitelných vlastností objektu. Chcete-li vrátit pole iterObjectklíče, předejte tento klíčové slovo jako argument Object.keys.
Například:
nechat objProperties = Objekt.keys(tento)
Přístup k tomuto poli vám umožní definovat iterační chování objektu.
Dále musíte sledovat iterace objektu. Toho lze dosáhnout pomocí proměnných čítače.
Například:
nechat propertyIndex = 0;
nechat childIndex = 0;
První proměnnou čítače budete používat ke sledování vlastností objektu a druhou ke sledování potomků vlastnosti.
Dále budete muset implementovat a vrátit další metoda.
Jako tak:
vrátit se {
další() {
// Následné bloky kódu jdou sem...
}
}
Uvnitř další budete muset zpracovat okrajový případ, který nastane, když byl celý objekt iterován. Abyste zvládli okrajový případ, musíte vrátit objekt s hodnota nastaven na nedefinováno a Hotovo nastaven na skutečný.
Pokud se tento případ nezpracuje, pokus o iteraci objektu povede k nekonečné smyčce.
Zde je návod, jak zacházet s okrajovým případem:
-li (propertyIndex > objProperties.délka- 1) {
vrátit se {
hodnota: nedefinováno,
Hotovo: skutečný,
};
}
Dále budete muset přistupovat k vlastnostem objektu a jejich podřízeným prvkům pomocí proměnných čítače, které jste deklarovali dříve.
Jako tak:
// Přístup k rodičovským a podřízeným vlastnostem
konst vlastnosti = tento[objProperties[propertyIndex]];
konst vlastnost = vlastnosti[childIndex];
Dále musíte implementovat nějakou logiku pro inkrementaci proměnných čítače. Logika by měla resetovat childIndex když v poli vlastnosti neexistují žádné další prvky a přesunete se na další vlastnost v objektu. Navíc by se měl zvýšit childIndex, pokud v poli aktuální vlastnosti stále existují prvky.
Například:
// Logika inkrementace indexu
if (childIndex >= properties.length - 1) {
// pokud v podřízeném poli nejsou žádné další prvky
// resetovatdítěindex
childIndex = 0;
// Přesun na další vlastnost
propertyIndex++;
} jiný {
// Přesune se na další prvek v podřízeném poli
childIndex++
}
Nakonec vraťte objekt s Hotovo vlastnost nastavena na Nepravdivé a hodnota vlastnost nastavena na aktuální podřízený prvek v iteraci.
Například:
vrátit se {
Hotovo: Nepravdivé,
hodnota: majetek,
};
Vaše hotovo Symbol.iterátor funkce by měla být podobná bloku kódu níže:
iterObject[Symbol.iterator] = funkce () {
konst objProperties = Objekt.keys(tento);
nechat propertyIndex = 0;
nechat childIndex = 0;vrátit se {
další: () => {
//Manipulace s pouzdrem okraje
-li (propertyIndex > objProperties.délka- 1) {
vrátit se {
hodnota: nedefinováno,
Hotovo: skutečný,
};
}// Přístup k rodičovským a podřízeným vlastnostem
konst vlastnosti = tento[objProperties[propertyIndex]];
konst vlastnost = vlastnosti[childIndex];// Logika inkrementace indexu
if (childIndex >= properties.length - 1) {
// pokud v podřízeném poli nejsou žádné další prvky
// resetovatdítěindex
childIndex = 0;
// Přesun na další vlastnost
propertyIndex++;
} jiný {
// Přesune se na další prvek v podřízeném poli
childIndex++
}
vrátit se {
Hotovo: Nepravdivé,
hodnota: majetek,
};
},
};
};
Běh a pro...z smyčka na iterObject po této implementaci nevyvolá chybu, protože implementuje a Symbol.iterátor metoda.
Ruční implementace iterátorů, jak jsme to udělali výše, se nedoporučuje, protože je velmi náchylná k chybám a může být obtížné spravovat logiku.
JavaScript generátory
Generátor JavaScriptu je funkce, kterou můžete kdykoli pozastavit a obnovit její provádění. Toto chování mu umožňuje vytvářet posloupnost hodnot v průběhu času.
Funkce generátoru, což je funkce, která vrací generátor, poskytuje alternativu k vytváření iterátorů.
Funkci generátoru můžete vytvořit stejným způsobem, jako byste vytvořili deklaraci funkce v JavaScriptu. Jediný rozdíl je v tom, že musíte připojit hvězdičku (*) na klíčové slovo function.
Například:
funkce* příklad () {
vrátit se"Generátor"
}
Když zavoláte normální funkci v JavaScriptu, vrátí hodnotu určenou jeho vrátit se klíčové slovo nebo nedefinováno v opačném případě. Funkce generátoru však nevrací žádnou hodnotu okamžitě. Vrací objekt Generator, který můžete přiřadit proměnné.
Chcete-li získat přístup k aktuální hodnotě iterátoru, zavolejte další metoda na objektu Generator.
Například:
konst gen = příklad();
console.log (gen.next()); // { hodnota: 'Generátor', Hotovo: skutečný }
Ve výše uvedeném příkladu je hodnota majetek pocházel z a vrátit se klíčové slovo, které účinně ukončí generátor. Toto chování je obecně nežádoucí u funkcí generátoru, protože to, co je odlišuje od normálních funkcí, je schopnost pozastavit a restartovat provádění.
Klíčové slovo výnosu
The výtěžek Klíčové slovo poskytuje způsob, jak procházet hodnotami v generátorech pozastavením provádění funkce generátoru a vrácením hodnoty, která za ním následuje.
Například:
funkce* příklad() {
výtěžek"Model S"
výtěžek"Model X"
výtěžek"Cyber Truck"vrátit se"Tesla"
}konst gen = příklad();
console.log (gen.next()); // { hodnota: 'Model S', Hotovo: Nepravdivé }
Ve výše uvedeném příkladu, když další metoda je volána na příklad generátor se pozastaví pokaždé, když narazí na výtěžek klíčové slovo. The Hotovo vlastnost bude také nastavena na Nepravdivé dokud nenarazí na a vrátit se klíčové slovo.
Volání na další metoda vícekrát na příklad generátor, abyste to demonstrovali, budete mít jako výstup následující.
console.log (gen.next()); // { hodnota: 'Model X', Hotovo: Nepravdivé }
console.log (gen.next()); // { hodnota: 'Kyber Truck', Hotovo: Nepravdivé }
console.log (gen.next()); // { hodnota: 'Tesla', Hotovo: skutečný }
řídicí panel.log (gen.next()); // { hodnota: nedefinováno, hotovo: pravda }
Můžete také iterovat přes objekt Generator pomocí pro...z smyčka.
Například:
pro (konst iterátor z gen) {
řídicí panel.log (iterátor);
}
/*
Model S
Model X
Cyber Truck
*/
Použití iterátorů a generátorů
I když se iterátory a generátory mohou zdát jako abstraktní pojmy, nejsou. Mohou být užitečné při práci s nekonečnými datovými toky a kolekcemi dat. Můžete je také použít k vytvoření jedinečných identifikátorů. Pod kapotou je také používají knihovny státní správy, jako je MobX-State-Tree (MST).