Iteratorët dhe gjeneratorët janë të dy veçori interesante të JavaScript. Dhe aq më tepër kur i përdorni ato së bashku. Në këtë postim në blog, le të shqyrtojmë të kuptuarit tonë për gjeneruesit dhe përsëritësit dhe të shohim se si mund t'i kombinojmë ato për të shkruar kod elegant JavaScript.

Iterator

E thënë thjesht, përsëritësi është një simbol që mund ta përdorni për ta bërë çdo objekt të përsëritur. Objektet iterable mund të përsëriten duke përdorur ciklin for...of. Së pari, le të shohim se cilat janë simbolet.

Simboli

Simboli është një lloj primitiv që garantohet të jetë unik. Një nga qëllimet e tij kryesore është të përdoret si çelës për koleksionet e fjalorëve (harta ose objekte të thjeshta). Gjithashtu, fakti që është gjithmonë unik e bën atë një kandidat të mirë për raste të tjera përdorimi interesante. Tani le të shqyrtojmë se çfarë dua të them me faktin se simboli është vërtet unik:

Kodi i mësipërm do të printojë:

// String Unique is not equal to Symbol(Unique)
// Symbol(Unique) is not equal to Symbol(Unique)

Së pari if krahason vargunnotSymbol me vlerë Unique me një shembull simboli me vlerën e përshkrimit Unique. Siç mund ta shihni, këto dy variabla nuk janë të barabarta. Një rast më interesant është if i dytë, ku po krahasojmë dy simbole që mund të duken identike në fillim. Megjithatë, edhe pse të dy simbolet kanë të njëjtën vlerë përshkrimi, ato nuk janë të barabarta. Përshkrimi përdoret vetëm për të përmirësuar lexueshmërinë e kodit tonë.

Përcaktimi i përsëritësve dhe iterabilëve

JavaScript ofron simbolin statik Symbol.iterator që mund ta përdorim për të bërë çdo objekt të përsëritur. Le të hedhim një vështrim në këtë shembull:

Së pari, le të përcaktojmë një klasë që do ta përsërisim:

PetShelter është një klasë e thjeshtë që përmban një grup objektesh të quajtur pets. Nën vetinë tonë pets, ne shtojmë një veçori tjetër duke përdorur Symbol.iterator si çelës. I caktojmë një funksion i cili kthen një shembull të ri të PetIterator.

Tani le të shohim se si duket përkufizimi i PetIterator:

PetIterator është vetëm një klasë tjetër që përmban vetëm një metodë - next. Çdo përsëritës kërkohet të ketë metodën next. Gjithashtu, kjo metodë duhet të kthejë një objekt që mund të përmbajë dy veti: done dhe value. Ju mund ta keni marrë me mend se për çfarë përdoren këto prona:

  • done është një veti boolean që tregon nëse kemi arritur apo jo në fund të përsëritjes.
  • value përdoret për të kthyer një vlerë të artikullit të përsëritur aktualisht.

Duke i përdorur ato së bashku

Tani që kemi përsëritësin dhe përsëritësin tonë, le të shohim se si mund t'i përdorim ato së bashku:

Shumë e thjeshtë apo jo? Cikli for...of krijoi dhe konsumoi automatikisht një shembull të ri të përsëritësit të ofruar nga klasa PetShelter.

Kodi i mësipërm do të printojë sa vijon në tastierë:

// { pet: { type: 'cat', name: 'Emma' } }
// { pet: { type: 'dog', name: 'Bubbles' } }
// { pet: { type: 'dog', name: 'Hank' } }
// { pet: { type: 'cat', name: 'Leo' } }

Gjenerator

Gjeneratorët janë një nga veçoritë e reja sintaksore të prezantuara me specifikimin EcmaScript 2015. Ashtu si async, gjeneratorët mund të përdoren për të kontrolluar rrjedhën e ekzekutimit të programit duke e ndalur dhe rifilluar atë siç e sheh klienti të arsyeshme. Le të hedhim një vështrim në një shembull se si do ta përkufizonim një gjenerator:

Siç mund ta shihni, gjeneratorët janë thjesht funksione të rregullta me disa dallime të vogla:

  • Për të përcaktuar një gjenerator, duhet të vendosni * pas fjalës kyçe function.
  • yield mund të përdoret brenda gjeneratorit për të ndalur ekzekutimin. Gjithashtu, çdo vlerë pas fjalës kyçe yield i kalon klientit që thërret gjeneratorin.

Tani le të shohim se si mund ta përdorim gjeneratorin tonë:

Këtu është dalja e kodit të mësipërm:

// Hi
// What's your name?
// I'm done here

Disa gjëra për t'u marrë parasysh këtu:

  • Thirrja e generatorSample() nuk ekzekuton funksionin e gjeneratorit, por në vend të kësaj kthen një shembull të ri të gjeneratorit.
  • Pasi kodi brenda gjeneratorit tonë ndeshet me yield, ai ndalon. Dhe ne përdorim metodën next të gjeneratorit për të vazhduar me ekzekutimin.

Ja se si duket struktura e objektit next:

{
value: 'Hi' //yielded value,
done: false //whether the generator is done executing or not
}

Përdorimi i gjeneratorëve për të krijuar përsëritës

Duket e njohur? Shpresojmë që tani po filloni të shihni një lidhje midis përsëritësve dhe gjeneratorëve. Sinqerisht, një nga arsyet kryesore pse gjeneratorët u prezantuan me ES 2015 ishte për ta bërë procesin e krijimit të përsëritësve shumë më të lehtë. Në fakt, gjithçka që duhet të bëjmë për ta kthyer PetShelter-në tonë në një iterable është ta bëjmë funksionin [ Symbol.iterator] të kthejë një shembull të ri të një gjeneratori. Tani le të shohim se si mund ta arrijmë këtë:

Ashtu si në shembullin e mëparshëm, kodi i mësipërm do të prodhojë daljen e mëposhtme:

// { pet: { type: 'cat', name: 'Emma' } }
// { pet: { type: 'dog', name: 'Bubbles' } }
// { pet: { type: 'dog', name: 'Hank' } }
// { pet: { type: 'cat', name: 'Leo' } }

Siç mund ta shihni, nuk kemi më nevojë të përcaktojmë një klasë të veçantë për PetIterator tonë. Gjithçka që duhej të përcaktonim ishte një gjenerator që përdor një lak for për të përsëritur mbi vetinë pets. Më pas, ne rregulluam funksionin [Symbol.iterator] për të kthyer një shembull të ri të gjeneratorit PetIterator.

Ne ishim në gjendje të përdornim gjeneratorin në vend të përsëritësit sepse gjeneratorët tashmë kanë një metodë të quajtur next që kthen një objekt me vetitë done dhe value.

Dhe kaq për këtë postim! Këtu kemi shqyrtuar shkurtimisht bazat e përsëritësve dhe gjeneratorëve dhe se si mund t'i përdorni ato për të krijuar lehtësisht objekte të përsëritura. Shpresoj ta keni gjetur të dobishëm këtë postim.

Faleminderit që lexuat!

Botuar fillimisht në https://isamatov.com më 24 korrik 2019.