Læsere som dig hjælper med at støtte MUO. Når du foretager et køb ved hjælp af links på vores websted, kan vi optjene en affiliate-kommission. Læs mere.

Iteration over dataindsamlinger ved hjælp af traditionelle loops kan hurtigt blive besværligt og langsomt, især når man har at gøre med enorme mængder data.

JavaScript Generatorer og Iteratorer giver en løsning til effektiv iteration over store datasamlinger. Ved at bruge dem kan du kontrollere iterationsflowet, give værdier én ad gangen og pause og genoptage iterationsprocessen.

Her vil du dække det grundlæggende og interne i en JavaScript iterator, og hvordan du kan generere en iterator manuelt og ved hjælp af en generator.

JavaScript iteratorer

En iterator er et JavaScript-objekt, der implementerer iterator-protokollen. Disse objekter gør det ved at have en Næste metode. Denne metode returnerer et objekt, der implementerer IteratorResultat interface.

Det IteratorResultat grænsefladen består af to egenskaber: Færdig og værdi. Det Færdig ejendom er en boolean, der vender tilbage

instagram viewer
falsk hvis iteratoren kan producere den næste værdi i sin rækkefølge eller rigtigt hvis iteratoren har fuldført sin sekvens.

Det værdi egenskaben er en JavaScript-værdi, der returneres af iteratoren under dens sekvens. Når en iterator fuldfører sin sekvens (hvornår Færdigrigtigt), vender denne egenskab tilbage udefineret.

Som navnet antyder, giver iteratorer dig mulighed for at "iterere" over JavaScript-objekter såsom arrays eller kort. Denne adfærd er mulig på grund af den iterable protokol.

I JavaScript er den iterable protokol en standard måde at definere objekter, som du kan iterere over, f.eks. for... af sløjfe.

For eksempel:

konst frugter = ["Banan", "Mango", "Æble", "Druer"];

til (konst iterator af frugter) {
konsol.log (iterator);
}

/*
Banan
Mango
Æble
Druer
*/

Dette eksempel gentager sig over frugter array ved hjælp af en for... af sløjfe. I hver iteration logger den den aktuelle værdi til konsollen. Dette er muligt, fordi arrays er iterable.

Nogle JavaScript-typer, såsom Arrays, Strings, Sæt og kort, er indbyggede iterables, fordi de (eller et af objekterne op ad deres prototypekæde) implementerer en @@iterator metode.

Andre typer, såsom objekter, kan ikke gentages som standard.

For eksempel:

konst iterObject = {
biler: ["Tesla", "BMW", "Toyota"],
dyr: ["Kat", "Hund", "Hamster"],
mad: ["burgere", "Pizza", "Pasta"],
};

til (konst iterator af iterObject) {
konsol.log (iterator);
}

// TypeError: iterObject kan ikke itereres

Dette eksempel viser, hvad der sker, når du forsøger at iterere over et objekt, der ikke kan itereres.

Gør et objekt gentageligt

For at gøre et objekt iterabelt, skal du implementere en Symbol.iterator metode på objektet. For at blive iterabel skal denne metode returnere et objekt, der implementerer IteratorResultat interface.

Det Symbol.iterator symbol tjener samme formål som @@iterator og kan bruges i flæng i "specifikation", men ikke i kode som @@iterator er ikke gyldig JavaScript-syntaks.

Kodeblokkene nedenfor giver et eksempel på, hvordan man gør et objekt iterbart ved hjælp af iterObjekt.

Først skal du tilføje Symbol.iterator metode til iterObjekt ved brug af en funktion erklæring.

Ligesom:

iterObject[Symbol.iterator] = fungere () {
// Efterfølgende kodeblokke går her...
}

Dernæst skal du have adgang til alle nøglerne i det objekt, du vil gøre iterbart. Du kan få adgang til tasterne ved hjælp af Objekt.nøgler metode, som returnerer en række af de talløse egenskaber for et objekt. At returnere en række af iterObjekt's nøgler, videregive det her nøgleord som argument for Objekt.nøgler.

For eksempel:

lade objEgenskaber = Objekt.nøgler(det her)

Adgang til dette array giver dig mulighed for at definere objektets iterationsadfærd.

Dernæst skal du holde styr på objektets iterationer. Du kan opnå dette ved at bruge tællervariable.

For eksempel:

lade ejendomsindeks = 0;
lade childIndex = 0;

Du vil bruge den første tællervariabel til at holde styr på objektegenskaberne og den anden til at holde styr på ejendommens børn.

Dernæst skal du implementere og returnere Næste metode.

Ligesom:

Vend tilbage {
Næste() {
// Efterfølgende kodeblokke går her...
}
}

Inde i Næste metode, skal du håndtere en kanttilfælde, der opstår, når hele objektet er blevet gentaget. For at håndtere kantkassen skal du returnere en genstand med værdi indstillet til udefineret og Færdig indstillet til rigtigt.

Hvis denne sag ikke håndteres, vil forsøg på at iterere over objektet resultere i en uendelig løkke.

Sådan håndterer du kantkassen:

hvis (ejendomsindeks > objEjendomme.længde- 1) {
Vend tilbage {
værdi: udefineret,
Færdig: rigtigt,
};
}

Dernæst skal du få adgang til objektegenskaberne og deres underordnede elementer ved hjælp af de tællervariabler, du har erklæret tidligere.

Ligesom:

// Adgang til overordnede og underordnede egenskaber
konst egenskaber = det her[objProperties[egenskabsindeks]];

konst ejendom = egenskaber[barnindeks];

Dernæst skal du implementere noget logik til at øge tællervariablerne. Logikken bør nulstille børneindeks når der ikke findes flere elementer i en egenskabs array og flytter til den næste egenskab i objektet. Derudover bør den stige børneindeks, hvis der stadig er elementer i den aktuelle ejendoms array.

For eksempel:

// Indeksøgende logik
if (childIndex >= properties.length - 1) {
// hvis der ikke er flere elementer i det underordnede array
// Nulstilbarnindeks
childIndex = 0;

// Flyt til næste ejendom
propertyIndex++;
} andet {
// Flyt til det næste element i det underordnede array
childIndex++
}

Til sidst returnerer du et objekt med Færdig egenskab sat til falsk og værdi egenskab sat til det aktuelle underordnede element i iterationen.

For eksempel:

Vend tilbage {
Færdig: falsk,
værdi: ejendom,
};

Din gennemførte Symbol.iterator funktionen skal ligne kodeblokken nedenfor:

iterObject[Symbol.iterator] = fungere () {
konst objEgenskaber = Objekt.nøgler(det her);
lade ejendomsindeks = 0;
lade childIndex = 0;

Vend tilbage {
Næste: () => {
//Håndtering kant sag
hvis (ejendomsindeks > objEjendomme.længde- 1) {
Vend tilbage {
værdi: udefineret,
Færdig: rigtigt,
};
}

// Adgang til overordnede og underordnede egenskaber
konst egenskaber = det her[objProperties[egenskabsindeks]];

konst ejendom = egenskaber[barnindeks];

// Indeksøgende logik
if (childIndex >= properties.length - 1) {
// hvis der ikke er flere elementer i det underordnede array
// Nulstilbarnindeks
childIndex = 0;

// Flyt til næste ejendom
propertyIndex++;
} andet {
// Flyt til det næste element i det underordnede array
childIndex++
}

Vend tilbage {
Færdig: falsk,
værdi: ejendom,
};
},
};
};

Kører a for... af sløjfe på iterObjekt efter denne implementering vil den ikke give en fejl, da den implementerer en Symbol.iterator metode.

Manuel implementering af iteratorer, som vi gjorde ovenfor, anbefales ikke, da det er meget fejltilbøjeligt, og logikken kan være svær at administrere.

JavaScript generatorer

En JavaScript-generator er en funktion, som du kan sætte på pause og genoptage dens udførelse på et hvilket som helst tidspunkt. Denne adfærd gør det muligt for den at producere en sekvens af værdier over tid.

En generatorfunktion, som er en funktion, der returnerer en Generator, giver et alternativ til at oprette iteratorer.

Du kan oprette en generatorfunktion på samme måde, som du ville oprette en funktionserklæring i JavaScript. Den eneste forskel er, at du skal tilføje en stjerne (*) til funktionsnøgleordet.

For eksempel:

fungere* eksempel () {
Vend tilbage"Generator"
}

Når du kalder en normal funktion i JavaScript, returnerer den værdien angivet af dens Vend tilbage søgeord eller udefineret Ellers. Men en generatorfunktion returnerer ikke nogen værdi med det samme. Det returnerer et Generator-objekt, som du kan tildele til en variabel.

For at få adgang til den aktuelle værdi af iteratoren skal du ringe til Næste metode på Generator-objektet.

For eksempel:

konst gen = eksempel();

console.log (gen.next()); // { værdi: 'Generator', Færdig: rigtigt }

I eksemplet ovenfor er værdi ejendom kom fra en Vend tilbage søgeord, hvilket effektivt afslutter generatoren. Denne adfærd er generelt uønsket med generatorfunktioner, da det, der adskiller dem fra normale funktioner, er evnen til at pause og genstarte udførelse.

Udbyttet Søgeord

Det udbytte nøgleord giver en måde at iterere gennem værdier i generatorer ved at sætte udførelsen af ​​en generatorfunktion på pause og returnere den værdi, der følger efter den.

For eksempel:

fungere* eksempel() {
udbytte"Model S"
udbytte"Model X"
udbytte"Cyberlastbil"

Vend tilbage"Tesla"
}

konst gen = eksempel();

console.log (gen.next()); // { værdi: 'Model S', Færdig: falsk }

I eksemplet ovenfor, når Næste metode bliver kaldt på eksempel generator, vil den pause hver gang den støder på udbytte søgeord. Det Færdig ejendom vil også blive sat til falsk indtil den støder på en Vend tilbage søgeord.

Ringer til Næste metode flere gange på eksempel generator for at demonstrere dette, har du følgende som output.

console.log (gen.next()); // { værdi: 'Model X', Færdig: falsk }
console.log (gen.next()); // { værdi: 'Cyberlastbil', Færdig: falsk }
console.log (gen.next()); // { værdi: 'Tesla', Færdig: rigtigt }

konsol.log (gen.next()); // { værdi: udefineret, udført: sand }

Du kan også iterere over et Generator-objekt ved hjælp af for... af sløjfe.

For eksempel:

til (konst iterator af gen) {
konsol.log (iterator);
}

/*
Model S
Model X
Cyber ​​lastbil
*/

Brug af iteratorer og generatorer

Selvom iteratorer og generatorer kan virke som abstrakte begreber, er de det ikke. De kan være nyttige, når du arbejder med uendelige datastrømme og dataindsamlinger. Du kan også bruge dem til at oprette unikke identifikatorer. Statsforvaltningsbiblioteker såsom MobX-State-Tree (MST) bruger dem også under hætten.