W laboratorium Parku Jurajskiego naukowcy analizują sekwencje DNA dinozaurów - element po elemencie, nigdy nie ładując całego genomu do pamięci. Iteratory i generatory w JavaScript działają podobnie - pozwalają przetwarzać dane element po elemencie, leniwie i efektywnie.
Każdy obiekt, który implementuje metodę
[Symbol.iterator](), jest iterowalny i może być użyty w pętli for...of.1// Tablice, stringi, Map, Set - są iterowalne z natury
2for (const char of 'ATCG') {
3 console.log(char); // A, T, C, G
4}
5
6for (const item of [1, 2, 3]) {
7 console.log(item); // 1, 2, 3
8}1const dinoEnclosure = {
2 dinosaurs: ['Rex', 'Blue', 'Delta', 'Echo'],
3
4 [Symbol.iterator]() {
5 let index = 0;
6 const dinos = this.dinosaurs;
7
8 return {
9 next() {
10 if (index < dinos.length) {
11 return { value: dinos[index++], done: false };
12 }
13 return { value: undefined, done: true };
14 }
15 };
16 }
17};
18
19// Teraz możemy użyć for...of!
20for (const dino of dinoEnclosure) {
21 console.log('Dinozaur:', dino);
22}
23
24// Oraz spread operator
25const allDinos = [...dinoEnclosure];
26console.log(allDinos); // ['Rex', 'Blue', 'Delta', 'Echo']1const park = { name: 'Jurassic', size: 'large', open: false };
2const species = ['T-Rex', 'Velociraptor', 'Triceratops'];
3
4// for...in - iteruje po KLUCZACH (obiektów i tablic)
5for (const key in park) {
6 console.log(key); // 'name', 'size', 'open'
7}
8
9for (const index in species) {
10 console.log(index); // '0', '1', '2' (stringi!)
11}
12
13// for...of - iteruje po WARTOŚCIACH (iterowalnych)
14for (const animal of species) {
15 console.log(animal); // 'T-Rex', 'Velociraptor', 'Triceratops'
16}
17
18// for...of NIE działa na zwykłych obiektach!
19// for (const val of park) {} // TypeError!
20// Ale działa na Object.entries():
21for (const [key, val] of Object.entries(park)) {
22 console.log(key, val);
23}Generatory to specjalne funkcje, które mogą pauzować swoje wykonanie i wznawiać je później.
1function* dinoGenerator() {
2 console.log('Generuję pierwszego dinozaura...');
3 yield 'T-Rex';
4
5 console.log('Generuję drugiego...');
6 yield 'Velociraptor';
7
8 console.log('Generuję trzeciego...');
9 yield 'Triceratops';
10
11 console.log('Koniec generacji!');
12}
13
14const gen = dinoGenerator();
15
16console.log(gen.next()); // { value: 'T-Rex', done: false }
17console.log(gen.next()); // { value: 'Velociraptor', done: false }
18console.log(gen.next()); // { value: 'Triceratops', done: false }
19console.log(gen.next()); // { value: undefined, done: true }1function* idGenerator(prefix) {
2 let id = 1;
3 while (true) {
4 yield prefix + '-' + String(id).padStart(3, '0');
5 id++;
6 }
7}
8
9const dinoIds = idGenerator('DINO');
10console.log(dinoIds.next().value); // 'DINO-001'
11console.log(dinoIds.next().value); // 'DINO-002'
12console.log(dinoIds.next().value); // 'DINO-003'
13// Nigdy się nie kończy - generuje na żądanie!1function* carnivores() {
2 yield 'T-Rex';
3 yield 'Velociraptor';
4}
5
6function* herbivores() {
7 yield 'Triceratops';
8 yield 'Brachiosaurus';
9}
10
11function* allDinosaurs() {
12 yield* carnivores();
13 yield* herbivores();
14}
15
16for (const dino of allDinosaurs()) {
17 console.log(dino);
18}
19// T-Rex, Velociraptor, Triceratops, Brachiosaurus1async function* fetchDinoPages(apiUrl) {
2 let page = 1;
3 let hasMore = true;
4
5 while (hasMore) {
6 const response = await fetch(apiUrl + '?page=' + page);
7 const data = await response.json();
8
9 yield data.results;
10
11 hasMore = data.hasNextPage;
12 page++;
13 }
14}
15
16// Użycie z for await...of
17async function loadAllDinos() {
18 for await (const batch of fetchDinoPages('/api/dinosaurs')) {
19 console.log('Załadowano grupę:', batch.length, 'dinozaurów');
20 }
21}1// 1. Lazy evaluation - przetwarzanie na żądanie
2function* fibonacci() {
3 let a = 0, b = 1;
4 while (true) {
5 yield a;
6 [a, b] = [b, a + b];
7 }
8}
9
10// Weź tylko 10 pierwszych
11const fib = fibonacci();
12const first10 = [];
13for (let i = 0; i < 10; i++) {
14 first10.push(fib.next().value);
15}
16console.log(first10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
17
18// 2. Paginacja - ładuj strony na żądanie
19function* paginate(items, pageSize) {
20 for (let i = 0; i < items.length; i += pageSize) {
21 yield items.slice(i, i + pageSize);
22 }
23}
24
25const allSpecies = ['A','B','C','D','E','F','G','H'];
26const pages = paginate(allSpecies, 3);
27console.log(pages.next().value); // ['A', 'B', 'C']
28console.log(pages.next().value); // ['D', 'E', 'F']
29console.log(pages.next().value); // ['G', 'H']"Iteratory i generatory to jak taśma produkcyjna w laboratorium" - mówi naukowiec. "Nie musisz przetwarzać wszystkiego naraz - dostajesz elementy dokładnie wtedy, gdy ich potrzebujesz!"