Tietokokoelmien iteroinnista perinteisten silmukoiden avulla voi nopeasti tulla hankalaa ja hidasta, varsinkin kun käsitellään valtavia tietomääriä.
JavaScript-generaattorit ja iteraattorit tarjoavat ratkaisun suurten tietokokoelmien tehokkaaseen iterointiin. Niiden avulla voit hallita iterointikulkua, tuottaa arvoja yksi kerrallaan ja keskeyttää iterointiprosessin ja jatkaa sitä.
Tässä käsitellään JavaScript-iteraattorin perusteita ja sisäisiä ominaisuuksia sekä kuinka voit luoda iteraattorin manuaalisesti ja käyttämällä generaattoria.
JavaScript-iteraattorit
Iteraattori on JavaScript-objekti, joka toteuttaa iteraattoriprotokollan. Nämä kohteet tekevät niin a Seuraava menetelmä. Tämä menetelmä palauttaa objektin, joka toteuttaa IteratorResult käyttöliittymä.
The IteratorResult käyttöliittymä sisältää kaksi ominaisuutta: tehty ja arvo. The tehty
ominaisuus on boolen arvo, joka palauttaa väärä jos iteraattori pystyy tuottamaan sekvenssinsä seuraavan arvon tai totta jos iteraattori on suorittanut sekvenssinsä.The arvo ominaisuus on JavaScript-arvo, jonka iteraattori palauttaa sarjansa aikana. Kun iteraattori suorittaa sekvenssinsä (kun tehtytotta), tämä ominaisuus palautuu määrittelemätön.
Kuten nimestä voi päätellä, iteraattorit antavat sinun "iteroida" JavaScript-objekteja, kuten taulukoita tai karttoja. Tämä toiminta on mahdollista iteroitavan protokollan ansiosta.
JavaScriptissä iteroitava protokolla on tavallinen tapa määrittää objektit, joita voit iteroida, kuten esim. varten...ja silmukka.
Esimerkiksi:
konst hedelmät = ["Banaani", "Mango", "Omena", "rypäleet"];
varten (konst iteraattori / hedelmät) {
konsoli.log (iteraattori);
}
/*
Banaani
Mango
Omena
Rypäleet
*/
Tämä esimerkki toistuu hedelmiä taulukko käyttäen a varten...ja silmukka. Jokaisessa iteraatiossa se kirjaa nykyisen arvon konsoliin. Tämä on mahdollista, koska taulukot ovat iteroitavissa.
Jotkut JavaScript-tyypit, kuten Arrays, Strings, Sarjat ja kartat, ovat sisäänrakennettuja iteroitavia, koska ne (tai jokin niiden prototyyppiketjussa olevista objekteista) toteuttavat an @@iteraattori menetelmä.
Muut tyypit, kuten objektit, eivät ole oletuksena iteroitavissa.
Esimerkiksi:
konst iterObject = {
autoja: ["Tesla", "BMW", "Toyota"],
eläimet: ["Kissa", "Koira", "Hamsteri"],
ruokaa: ["Hampurilaiset", "Pizza", "Pasta"],
};varten (konst iteraattori / iterObject) {
konsoli.log (iteraattori);
}
// TypeError: iterObject ei ole iteroitavissa
Tämä esimerkki osoittaa, mitä tapahtuu, kun yrität iteroida objektia, joka ei ole iteroitavissa.
Objektin tekeminen iteroitavaksi
Jotta objekti olisi iteroitava, sinun on toteutettava a Symboli.iteraattori menetelmä objektiin. Jotta tämä menetelmä olisi iteroitava, sen on palautettava objekti, joka toteuttaa IteratorResult käyttöliittymä.
The Symboli.iteraattori symboli palvelee samaa tarkoitusta kuin @@iteraattori ja sitä voidaan käyttää vaihtokelpoisesti "spesifikaatiossa", mutta ei koodissa as @@iteraattori ei ole kelvollinen JavaScript-syntaksi.
Alla olevat koodilohkot tarjoavat esimerkin siitä, kuinka objektista tehdään iteroitava käyttämällä iterObject.
Lisää ensin Symboli.iteraattori menetelmään iterObject käyttämällä toiminto ilmoitus.
Niin kuin:
iterObject[Symboli.iterator] = toiminto () {
// Myöhemmät koodilohkot menevät tähän...
}
Seuraavaksi sinun on käytettävä kaikkia avaimia objektissa, josta haluat tehdä iteroitavan. Voit käyttää avaimia käyttämällä Objekti.avaimet menetelmä, joka palauttaa joukon objektin lukemattomista ominaisuuksista. Palauttaaksesi joukon iterObject's avaimet, ohita Tämä avainsana argumenttina Objekti.avaimet.
Esimerkiksi:
antaa objProperties = Esine.keys(Tämä)
Pääsy tähän taulukkoon antaa sinun määrittää objektin iteraatiokäyttäytymisen.
Seuraavaksi sinun on seurattava kohteen iteraatioita. Voit saavuttaa tämän käyttämällä laskurimuuttujia.
Esimerkiksi:
antaa propertyIndex = 0;
antaa lapsiindeksi = 0;
Käytät ensimmäistä laskurimuuttujaa seurataksesi kohteen ominaisuuksia ja toista pitääksesi kirjaa omaisuuden lapsista.
Seuraavaksi sinun on otettava käyttöön ja palautettava Seuraava menetelmä.
Niin kuin:
palata {
Seuraava() {
// Myöhemmät koodilohkot menevät tähän...
}
}
Sisällä Seuraava menetelmää, sinun on käsiteltävä reunatapausta, joka tapahtuu, kun koko objekti on iteroitu. Reunakotelon käsittelemiseksi sinun on palautettava objekti, jossa on arvo asetettu määrittelemätön ja tehty asetettu totta.
Jos tätä tapausta ei käsitellä, objektin iteroinnin yrittäminen johtaa äärettömään silmukkaan.
Näin käsittelet reunatapausta:
jos (propertyIndex > objOminaisuudet.pituus- 1) {
palata {
arvo: määrittelemätön,
tehty: totta,
};
}
Seuraavaksi sinun on käytettävä objektin ominaisuuksia ja niiden alielementtejä käyttämällä aiemmin määrittämiäsi laskurimuuttujia.
Niin kuin:
// Pääsy ylä- ja alatason ominaisuuksiin
konst ominaisuudet = Tämä[objProperties[propertyIndex]];
konst ominaisuus = ominaisuudet[lapsiindeksi];
Seuraavaksi sinun on otettava käyttöön logiikka laskurimuuttujien lisäämiseksi. Logiikan pitäisi nollata lapsihakemisto kun ominaisuuden taulukossa ei ole enää elementtejä ja siirrytään objektin seuraavaan ominaisuuteen. Lisäksi sen pitäisi kasvaa lapsihakemisto, jos nykyisen ominaisuuden taulukossa on vielä elementtejä.
Esimerkiksi:
// Indeksointilogiikka
if (childIndex >= properties.length - 1) {
// jos lapsitaulukossa ei ole enää elementtejä
// nollaalapsiindeksi
lapsiindeksi = 0;
// Siirry seuraavaan omaisuuteen
propertyIndex++;
} muu {
// Siirry alitaulukon seuraavaan elementtiin
lapsiindeksi++
}
Palauta lopuksi objekti tehty ominaisuus asetettu väärä ja arvo ominaisuus asetetaan iteraation nykyiselle lapsielementille.
Esimerkiksi:
palata {
tehty: väärä,
arvo: omaisuus,
};
Olet valmis Symboli.iteraattori toiminnon tulisi olla samanlainen kuin alla oleva koodilohko:
iterObject[Symboli.iterator] = toiminto () {
konst objProperties = Esine.keys(Tämä);
antaa propertyIndex = 0;
antaa lapsiindeksi = 0;palata {
Seuraava: () => {
//Käsittelee reunatapausta
jos (propertyIndex > objOminaisuudet.pituus- 1) {
palata {
arvo: määrittelemätön,
tehty: totta,
};
}// Pääsy ylä- ja alatason ominaisuuksiin
konst ominaisuudet = Tämä[objProperties[propertyIndex]];
konst ominaisuus = ominaisuudet[lapsiindeksi];// Indeksointilogiikka
if (childIndex >= properties.length - 1) {
// jos lapsitaulukossa ei ole enää elementtejä
// nollaalapsiindeksi
lapsiindeksi = 0;
// Siirry seuraavaan omaisuuteen
propertyIndex++;
} muu {
// Siirry alitaulukon seuraavaan elementtiin
lapsiindeksi++
}
palata {
tehty: väärä,
arvo: omaisuus,
};
},
};
};
Juoksemassa a varten...ja silmukka päälle iterObject tämän toteutuksen jälkeen ei aiheuta virhettä, koska se toteuttaa a Symboli.iteraattori menetelmä.
Iteraattorien manuaalista käyttöönottoa, kuten yllä teimme, ei suositella, koska se on erittäin virhealtista ja logiikkaa voi olla vaikea hallita.
JavaScript-generaattorit
JavaScript-generaattori on toiminto, jonka voit keskeyttää ja jatkaa sen suorittamista milloin tahansa. Tämän toiminnan ansiosta se voi tuottaa arvosarjan ajan kuluessa.
Generaattorifunktio, joka palauttaa generaattorin, tarjoaa vaihtoehdon iteraattorien luomiselle.
Voit luoda generaattorifunktion samalla tavalla kuin luot funktion määrityksen JavaScriptissä. Ainoa ero on, että sinun on liitettävä tähti (*) funktion avainsanaan.
Esimerkiksi:
toiminto* esimerkki () {
palata"Generaattori"
}
Kun kutsut normaalia funktiota JavaScriptissä, se palauttaa sen määrittämän arvon palata avainsana tai määrittelemätön muuten. Mutta generaattorifunktio ei palauta mitään arvoa välittömästi. Se palauttaa Generator-objektin, jonka voit määrittää muuttujalle.
Voit tarkastella iteraattorin nykyistä arvoa soittamalla Seuraava menetelmä Generator-objektissa.
Esimerkiksi:
konst gen = esimerkki();
console.log (gen.next()); // { arvo: 'Generaattori', tehty: totta }
Yllä olevassa esimerkissä arvo omaisuus on peräisin a palata avainsana, joka lopettaa generaattorin tehokkaasti. Tämä käyttäytyminen on yleensä ei-toivottavaa generaattoritoimintojen kanssa, koska se erottaa ne normaaleista toiminnoista on kyky keskeyttää ja käynnistää suoritus uudelleen.
Tuoton avainsana
The tuotto avainsana tarjoaa tavan toistaa generaattoreiden arvoja keskeyttämällä generaattorifunktion suorittamisen ja palauttamalla sitä seuraavan arvon.
Esimerkiksi:
toiminto* esimerkki() {
tuotto"malli S"
tuotto"malli X"
tuotto"Cyber Truck"palata"Tesla"
}konst gen = esimerkki();
console.log (gen.next()); // { arvo: "Model S", tehty: väärä }
Yllä olevassa esimerkissä, kun Seuraava menetelmää kutsutaan esimerkki generaattori, se pysähtyy aina, kun se kohtaa tuotto avainsana. The tehty kiinteistö asetetaan myös väärä kunnes se kohtaa a palata avainsana.
Soittamalla Seuraava menetelmä useita kertoja esimerkki generaattori osoittaaksesi tämän, tulosteena on seuraava.
console.log (gen.next()); // { arvo: "malli X", tehty: väärä }
console.log (gen.next()); // { arvo: "Cyber Truck", tehty: väärä }
console.log (gen.next()); // { arvo: "Tesla", tehty: totta }
konsoli.log (gen.next()); // { arvo: määrittelemätön, tehty: tosi }
Voit myös iteroida Generator-objektin yli käyttämällä varten...ja silmukka.
Esimerkiksi:
varten (konst iteraattori / gen) {
konsoli.log (iteraattori);
}
/*
Malli S
Malli X
Kyberauto
*/
Iteraattorien ja generaattoreiden käyttö
Vaikka iteraattorit ja generaattorit saattavat tuntua abstrakteilta käsitteiltä, ne eivät ole sitä. Ne voivat olla hyödyllisiä, kun työskentelet äärettömien tietovirtojen ja tietokokoelmien kanssa. Voit myös käyttää niitä yksilöllisten tunnisteiden luomiseen. Valtionhallintakirjastot, kuten MobX-State-Tree (MST), käyttävät niitä myös konepellin alla.