JavaScript-də Iterators və Generators
-
JavaScript-də iterators və generators, məlumatların ardıcıl emalını daha çevik və oxunaqlı şəkildə idarə etməyə imkan verir. Bu anlayışlar ES6 (ECMAScript 2015) ilə JavaScript dilinə əlavə edilib və xüsusilə custom iterable strukturların yaradılmasında, lazy evaluation və asinxron proqramlaşdırma sahələrində böyük əhəmiyyət daşıyır.
1. Iteration Protocols (İterasiya Protokolları)
JavaScript-də iterasiya aşağıdakı iki əsas protokol üzərindən qurulur:
1.1 Iterable protokolu
Bu protokol, obyektin
Symbol.iterator
adlı xüsusi bir metodu vasitəsilə iterasiya edilə biləcəyini göstərir. Bu metod geriyə bir iterator obyekt qaytarmalıdır.1.2 Iterator protokolu
Iterator obyektində
next()
metodu mövcud olur. Bu metod hər çağırıldıqda obyektin növbəti dəyərini və iterasiyanın bitib-bitmədiyini bildirən{ value, done }
şəklində obyekt qaytarır.
String
üzərində iterator istifadəconst text = "Rhyme"; const it = text[Symbol.iterator](); console.log(it.next()); // { value: 'R', done: false }
Array elementlərini iterator ilə çap edilməsi
const cities = ["Sofia", "New Delhi", "Tokyo"]; const iterableCities = cities[Symbol.iterator](); let result = iterableCities.next(); while (!result.done) { console.log(result.value); result = iterableCities.next(); }
Öz Iteratorumuzu yaratmaq
class Polygon { constructor(...sides) { this.sides = sides; } [Symbol.iterator]() { let index = 0; return { next: () => { if (index < this.sides.length){ return { value: this.sides[index++], done: false } } return { done: true } } }; } } const poly = new Polygon(1, 2, 3, 4, 5); for (let side of poly) { console.log(side); }
2 Generators ilə tanışlıq
Generatorlar
function*
sintaksisi ilə yaradılır. Onlaryield
açar sözü ilə bir-bir dəyərlər qaytarır.function* generator() { yield 1; yield 2; yield 3; } const gen = generator(); console.log(gen.next().value); // 1 console.log(gen.next().value); // 2
Class daxilində generator
class Polygon { constructor(...sides) { this.sides = sides; } *[Symbol.iterator]() { for (const side of this.sides) { yield side; } } }
ID Generatoru
function* idMaker() { let id = 0; while (true) { yield id++; } } const it = idMaker(); console.log(it.next().value); // 0 console.log(it.next().value); // 1
Parametr ötürmək
function* observerGenerator() { console.log('Generator created'); while (true) { const value = yield; console.log(`Value passed: ${value}`); } } const it = observerGenerator(); it.next(); // Başlamaq üçün ilk çağırış it.next(42); // Console: Value passed: 42
yield*
ilə generatorlar içində generatorfunction* citiesGenerator() { yield 'Paris'; yield* ['Rome', 'Florence', 'Berlin']; } const it = citiesGenerator(); for (const city of it) { console.log(city); }
Özünü yoxlmaq üçün mövzu üzrə tapşırıqlar
Misal 1: Sadə ədədləri verən generator funksiyası yazın
Bu məşqdə məqsəd, sadə ədədləri (prime numbers) ardıcıl olaraq verə bilən bir generator funksiyası yazmaqdır. Sadə ədədlər yalnız 1 və özündən başqa heç bir ədədə bölünməyən ədədlərdir (məsələn: 2, 3, 5, 7, 11, 13 və s.).
Yardımçı funksiya:
isPrime(num)
const isPrime = num => { for (let i = 2; i < num; i++) { if (num % i === 0) { return false; } } return num > 1; };
const isPrime = num => { for (let i = 2; i < num; i++) { if (num % i === 0) return false; } return num > 1; } function* primeNumbersGenerator() { let num = 2; while (true) { if (isPrime(num)) yield num; num++; } } const primes = primeNumbersGenerator(); console.log(primes.next().value); // 2 console.log(primes.next().value); // 3 console.log(primes.next().value); // 5
Misal 2: Generator ilə sual-cavab prosesi
Bu məşqdə bir generator funksiyası yaradaraq, onun necə sual verə biləcəyini və sonradan həmin suala verilən cavabı
next()
metodu ilə qəbul edərək qiymətləndirəcəyini öyrənəcəyik. solveRiddle adlı generator bizə bir sual qaytarmalı (misal: What’s the Answer to the Ultimate Question of Life, the Universe, and Everything?) sonra daxil olan cavaba uyğun olaraq novbəti çağırışdatrue
və yafalse
qaytarmalıdır. Misal üçün42
yazılıbsa true.function* solveRiddle() { const question = "What's the Answer to the Ultimate Question of Life, the Universe, and Everything?"; const answer = yield question; yield answer === 42; } const it = solveRiddle(); console.log(it.next().value); // sualı qaytarır console.log(it.next(42).value); // true
Misal 3: Massivin Flatten olunması (Yastılanması)
Bu məşqdə məqsəd nested array-ləri (yəni iç-içə massivləri) istədiyimiz qədər dərinlikdə “yastılaşdırmaqdır” – yəni içərisindəki bütün elementləri tək səviyyəli array halına salmaqdır.
flatten
adlı bir generator function yazılmalıdır ki, o daxil olan array-in içərisindəki elementləriyield
etməklə tək-tək qaytarsın. Əgər elementarray-
dirsə vədepth
> 0-dırsa, həmin elementi yenidənflatten
funksiyası ilə rekursiv şəkildə açmaq lazımdır (yield* istifadə etməklə).function* flatten(array, depth = 1) { for (const item of array) { if (Array.isArray(item) && depth > 0) { yield* flatten(item, depth - 1); } else { yield item; } } } const arr = [1, 2, [3, 4, [5, 6]]]; const flattened = [...flatten(arr, Infinity)]; console.log(flattened); // [1, 2, 3, 4, 5, 6]
Nəticə
JavaScript-də
Iterators
vəGenerators
mövzusu, inkişaf etmiş iterasiya strukturları və performanslı həllər yaratmaq üçün güclü vasitələr təklif edir. Onlar həm custom data structures, həm də lazy evaluation, stream processing, və asinxron əməliyyatlar üçün vacibdir. -
function* observerGenerator() { while (true) { console.log(`Value passed: ${yield}`); } } const obs = observerGenerator(); obs.next('first'); obs.next('second'); obs.next('third');
Gəlin bu generator funksiyasının necə işlədiyini addım-addım izah edək ki, niyə yalnız
"second"
və"third"
dəyərləri ekrana çıxır, anlaşılsın.
Addım-addım izah:
Addım 1: Generator yaradılır
const obs = observerGenerator();
Bu sətir
observerGenerator
generator funksiyasını başlatmır, sadəcəobs
adlı generator obyektini yaradır.
Addım 2:
obs.next('first')
Generator ilk dəfə
next('first')
ilə işə salınır.obs.next('first');
Vacib məqam: Generatorlar
yield
sətrinə çatana qədər kodu işlətməyə başlayır. Bizim generatorda ilk sətir bu olur:console.log(`Value passed: ${yield}`);
Burada
yield
ifadəsi özündə dəyəri saxlayır, amma ilk dəfənext()
çağırıldıqda,yield
-ə verilən dəyər gözlənilmir, çünki generator hələ dayanmamışdı.- Yəni
obs.next('first')
çağırıldıqda:- Generator işə düşür,
yield
-ə gəlib dayanır,- Amma
yield
-ə dəyər ötürülmür, ona görə dəconsole.log(...)
işləmir.
Addım 3:
obs.next('second')
İndi isə
yield
artıq dayandığı yerdə gözləyir. Bizsecond
dəyərini ötürürük:obs.next('second');
- Bu dəyər birbaşa
yield
ifadəsinə ötürülür console.log(...)
artıq işləyir və:Value passed: second
Addım 4:
obs.next('third')
Bu dəfə eyni proses təkrar olunur:
obs.next('third');
third
dəyəri yenəyield
-ə ötürülür,console.log(...)
işləyir:Value passed: third
Nəticə:
Yalnız ikinci və üçüncü
next()
çağırışlarındaconsole.log()
işləyir, çünki:- İlk
next()
generatoruyield
-ə qədər aparır və heç bir dəyər ötürmür (sadəcə start verir). - Sonrakı
next(dəyər)
çağırışları isəyield
-ə dəyər ötürür və nəticədəconsole.log()
işləyir.
Qısa xülasə:
next()
çağırışıyield
-ə nə ötürülür?Nəticə obs.next('first')
Heç nə console.log()
işləmirobs.next('second')
'second'
Çıxış: Value passed: second
obs.next('third')
'third'
Çıxış: Value passed: third
- Yəni
Bilik paylaşdıqca artan bir sərvətdir