JavaScript generator funksiyalari va iterator protokoli bo'yicha to'liq qo'llanma. Maxsus iteratorlar yaratish va JavaScript ilovalaringizni yaxshilashni o'rganing.
JavaScript Generator Funksiyalari: Iterator Protokolini O'zlashtirish
ECMAScript 6 (ES6) da taqdim etilgan JavaScript generator funksiyalari iteratorlarni yanada ixcham va o'qilishi oson usulda yaratish uchun kuchli mexanizmni taqdim etadi. Ular iterator protokoli bilan uzviy bog'lanib, murakkab ma'lumotlar tuzilmalari va asinxron amallarni osonlik bilan bajara oladigan maxsus iteratorlar yaratish imkonini beradi. Ushbu maqolada generator funksiyalarining nozikliklari, iterator protokoli va ularning qo'llanilishini ko'rsatuvchi amaliy misollar chuqur o'rganiladi.
Iterator Protokolini Tushunish
Generator funksiyalariga sho'ng'ishdan oldin, JavaScript-dagi iteratsiyalanuvchi ma'lumotlar tuzilmalari uchun asos bo'lgan iterator protokolini tushunish juda muhim. Iterator protokoli obyektni qanday qilib iteratsiya qilish mumkinligini, ya'ni uning elementlariga ketma-ket kirish mumkinligini belgilaydi.
Iteratsiyalanuvchi Protokol
Agar obyekt @@iterator usulini (Symbol.iterator) amalga oshirsa, u iteratsiyalanuvchi hisoblanadi. Bu usul iterator obyektini qaytarishi kerak.
Oddiy iteratsiyalanuvchi obyekt misoli:
const myIterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
return {
next() {
if (index < myIterable.data.length) {
return { value: myIterable.data[index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
};
for (const item of myIterable) {
console.log(item); // Output: 1, 2, 3
}
Iterator Protokoli
Iterator obyekti next() usuliga ega bo'lishi kerak. next() usuli ikkita xususiyatga ega obyektni qaytaradi:
value: Ketma-ketlikdagi keyingi qiymat.done: Iterator ketma-ketlikning oxiriga yetganligini ko'rsatuvchi mantiqiy (boolean) qiymat.truetugaganligini bildiradi;falseesa olinadigan qiymatlar hali borligini anglatadi.
Iterator protokoli JavaScript-ning for...of sikllari va spread operatori (...) kabi o'rnatilgan xususiyatlariga maxsus ma'lumotlar tuzilmalari bilan uzluksiz ishlash imkonini beradi.
Generator Funksiyalari Bilan Tanishtirish
Generator funksiyalari iteratorlarni yaratishning yanada nafis va ixcham usulini taqdim etadi. Ular function* sintaksisi yordamida e'lon qilinadi.
Generator Funksiyalarining Sintaksisi
Generator funksiyasining asosiy sintaksisi quyidagicha:
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}
const iterator = myGenerator();
console.log(iterator.next()); // Output: { value: 1, done: false }
console.log(iterator.next()); // Output: { value: 2, done: false }
console.log(iterator.next()); // Output: { value: 3, done: false }
console.log(iterator.next()); // Output: { value: undefined, done: true }
Generator funksiyalarining asosiy xususiyatlari:
- Ular
functiono'rnigafunction*bilan e'lon qilinadi. - Ular bajarilishni to'xtatib turish va qiymat qaytarish uchun
yieldkalit so'zidan foydalanadi. - Iteratorga har safar
next()chaqirilganda, generator funksiyasi o'zi to'xtagan joydan bajarilishni davom ettiradi va keyingiyieldiborasiga duch kelguncha yoki funksiya qaytgunicha ishlaydi. - Generator funksiyasi bajarilishni tugatganda (oxiriga yetganda yoki
returniborasiga duch kelganda), qaytarilgan obyektningdonexususiyatitruebo'ladi.
Generator Funksiyalari Iterator Protokolini Qanday Amalga Oshiradi
Generator funksiyasini chaqirganingizda, u darhol bajarilmaydi. Buning o'rniga, u iterator obyektini qaytaradi. Bu iterator obyekti avtomatik tarzda iterator protokolini amalga oshiradi. Har bir yield iborasi iteratorning next() usuli uchun qiymat hosil qiladi. Generator funksiyasi ichki holatni boshqaradi va o'zining rivojlanishini kuzatib boradi, bu esa maxsus iteratorlarni yaratishni soddalashtiradi.
Generator Funksiyalarining Amaliy Misollari
Keling, generator funksiyalarining kuchi va ko'p qirraliligini namoyish etuvchi ba'zi amaliy misollarni ko'rib chiqaylik.
1. Sonlar Ketma-ketligini Yaratish
Ushbu misol belgilangan oraliqdagi sonlar ketma-ketligini yaratadigan generator funksiyasini qanday yaratishni ko'rsatadi.
function* numberSequence(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
const sequence = numberSequence(10, 15);
for (const num of sequence) {
console.log(num); // Output: 10, 11, 12, 13, 14, 15
}
2. Daraxt Tuzilmasi Bo'yicha Iteratsiya Qilish
Generator funksiyalari, ayniqsa, daraxtlar kabi murakkab ma'lumotlar tuzilmalarini aylanib chiqish uchun foydalidir. Ushbu misol binar daraxt tugunlari bo'ylab iteratsiya qilishni ko'rsatadi.
class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
function* treeTraversal(node) {
if (node) {
yield* treeTraversal(node.left); // Recursive call for left subtree
yield node.value; // Yield the current node's value
yield* treeTraversal(node.right); // Recursive call for right subtree
}
}
// Create a sample binary tree
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
// Iterate over the tree using the generator function
const treeIterator = treeTraversal(root);
for (const value of treeIterator) {
console.log(value); // Output: 4, 2, 5, 1, 3 (In-order traversal)
}
Ushbu misolda, yield* boshqa iteratorga topshirish uchun ishlatiladi. Bu rekursiv iteratsiya uchun juda muhim bo'lib, generatorga butun daraxt tuzilmasini aylanib chiqish imkonini beradi.
3. Asinxron Amallarni Bajarish
Generator funksiyalarini asinxron amallarni ketma-ket va o'qilishi osonroq tarzda bajarish uchun Promise'lar bilan birlashtirish mumkin. Bu, ayniqsa, API'dan ma'lumotlarni olish kabi vazifalar uchun foydalidir.
async function fetchData(url) {
const response = await fetch(url);
const data = await response.json();
return data;
}
function* dataFetcher(urls) {
for (const url of urls) {
try {
const data = yield fetchData(url);
yield data;
} catch (error) {
console.error("Error fetching data from", url, error);
yield null; // Or handle the error as needed
}
}
}
async function runDataFetcher() {
const urls = [
"https://jsonplaceholder.typicode.com/todos/1",
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/users/1"
];
const dataIterator = dataFetcher(urls);
for (const promise of dataIterator) {
const data = await promise; // Await the promise returned by yield
if (data) {
console.log("Fetched data:", data);
} else {
console.log("Failed to fetch data.");
}
}
}
runDataFetcher();
Ushbu misol asinxron iteratsiyani namoyish etadi. dataFetcher generator funksiyasi olingan ma'lumotlarga aylantiriladigan Promise'larni hosil qiladi. Keyin runDataFetcher funksiyasi ushbu promise'lar orqali iteratsiya qilib, ma'lumotlarni qayta ishlashdan oldin har birini kutadi. Ushbu yondashuv asinxron kodni sinxronroq ko'rinishga keltirib, uni soddalashtiradi.
4. Cheksiz Ketma-ketliklar
Generatorlar hech qachon tugamaydigan ketma-ketliklar bo'lgan cheksiz ketma-ketliklarni ifodalash uchun juda mos keladi. Ular faqat so'ralganda qiymatlarni hosil qilganligi sababli, ular haddan tashqari xotirani iste'mol qilmasdan cheksiz uzun ketma-ketliklarni bajara oladi.
function* fibonacciSequence() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fibonacci = fibonacciSequence();
// Get the first 10 Fibonacci numbers
for (let i = 0; i < 10; i++) {
console.log(fibonacci.next().value); // Output: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
}
Ushbu misol cheksiz Fibonachchi ketma-ketligini qanday yaratishni ko'rsatadi. Generator funksiyasi Fibonachchi sonlarini cheksiz ravishda hosil qilishda davom etadi. Amalda, cheksiz sikl yoki xotira tugashini oldini olish uchun odatda olinadigan qiymatlar sonini cheklashingiz kerak bo'ladi.
5. Maxsus `range` Funksiyasini Amalga Oshirish
Generatorlardan foydalanib, Python'ning o'rnatilgan `range` funksiyasiga o'xshash maxsus `range` funksiyasini yarating.
function* range(start, end, step = 1) {
if (step > 0) {
for (let i = start; i < end; i += step) {
yield i;
}
} else if (step < 0) {
for (let i = start; i > end; i += step) {
yield i;
}
}
}
// Generate numbers from 0 to 5 (exclusive)
for (const num of range(0, 5)) {
console.log(num); // Output: 0, 1, 2, 3, 4
}
// Generate numbers from 10 to 0 (exclusive) in reverse order
for (const num of range(10, 0, -2)) {
console.log(num); // Output: 10, 8, 6, 4, 2
}
Generator Funksiyalarining Ilg'or Texnikalari
1. Generator Funksiyalarida `return`dan Foydalanish
Generator funksiyasidagi return iborasi iteratsiyaning tugashini bildiradi. return iborasiga duch kelinganda, iteratorning next() usulining done xususiyati true ga o'rnatiladi va value xususiyati return iborasi tomonidan qaytarilgan qiymatga (agar mavjud bo'lsa) o'rnatiladi.
function* myGenerator() {
yield 1;
yield 2;
return 3; // End of iteration
yield 4; // This will not be executed
}
const iterator = myGenerator();
console.log(iterator.next()); // Output: { value: 1, done: false }
console.log(iterator.next()); // Output: { value: 2, done: false }
console.log(iterator.next()); // Output: { value: 3, done: true }
console.log(iterator.next()); // Output: { value: undefined, done: true }
2. Generator Funksiyalarida `throw`dan Foydalanish
Iterator obyektidagi throw usuli generator funksiyasiga istisno (exception) kiritish imkonini beradi. Bu xatolarni bartaraf etish yoki generator ichidagi maxsus shartlar haqida signal berish uchun foydali bo'lishi mumkin.
function* myGenerator() {
try {
yield 1;
yield 2;
} catch (error) {
console.error("Caught an error:", error);
}
yield 3;
}
const iterator = myGenerator();
console.log(iterator.next()); // Output: { value: 1, done: false }
iterator.throw(new Error("Something went wrong!")); // Inject an error
console.log(iterator.next()); // Output: { value: 3, done: false }
console.log(iterator.next()); // Output: { value: undefined, done: true }
3. `yield*` Yordamida Boshqa Iteratsiyalanuvchiga Topshirish
Daraxtni aylanib chiqish misolida ko'rinib turganidek, yield* sintaksisi boshqa iteratsiyalanuvchiga (yoki boshqa generator funksiyasiga) topshirish imkonini beradi. Bu iteratorlarni birlashtirish va murakkab iteratsiya mantig'ini soddalashtirish uchun kuchli xususiyatdir.
function* generator1() {
yield 1;
yield 2;
}
function* generator2() {
yield* generator1(); // Delegate to generator1
yield 3;
yield 4;
}
const iterator = generator2();
for (const value of iterator) {
console.log(value); // Output: 1, 2, 3, 4
}
Generator Funksiyalaridan Foydalanishning Afzalliklari
- O'qilishi Osonligi Yaxshilangan: Generator funksiyalari qo'lda yozilgan iteratorlarga nisbatan iterator kodini ixchamroq va tushunarliroq qiladi.
- Asinxron Dasturlashni Soddalashtirish: Ular asinxron amallarni sinxron uslubda yozishga imkon berib, asinxron kodni soddalashtiradi.
- Xotira Samaradorligi: Generator funksiyalari qiymatlarni talabga binoan ishlab chiqaradi, bu ayniqsa katta hajmdagi ma'lumotlar to'plamlari yoki cheksiz ketma-ketliklar uchun foydalidir. Ular butun ma'lumotlar to'plamini bir vaqtning o'zida xotiraga yuklashdan saqlaydi.
- Kodning Qayta Ishlatilishi: Ilovangizning turli qismlarida ishlatilishi mumkin bo'lgan qayta foydalanishga yaroqli generator funksiyalarini yaratishingiz mumkin.
- Moslashuvchanlik: Generator funksiyalari turli ma'lumotlar tuzilmalari va iteratsiya naqshlarini bajara oladigan maxsus iteratorlarni yaratish uchun moslashuvchan usulni taqdim etadi.
Generator Funksiyalaridan Foydalanish Bo'yicha Eng Yaxshi Amaliyotlar
- Tavsiflovchi nomlardan foydalaning: Kodning o'qilishini yaxshilash uchun generator funksiyalaringiz va o'zgaruvchilaringiz uchun mazmunli nomlarni tanlang.
- Xatolarni to'g'ri boshqaring: Kutilmagan xatti-harakatlarning oldini olish uchun generator funksiyalaringiz ichida xatolarni qayta ishlashni joriy qiling.
- Cheksiz ketma-ketliklarni cheklang: Cheksiz ketma-ketliklar bilan ishlaganda, cheksiz sikllar yoki xotira tugashini oldini olish uchun olinadigan qiymatlar sonini cheklash mexanizmiga ega ekanligingizga ishonch hosil qiling.
- Ishlash samaradorligini hisobga oling: Generator funksiyalari odatda samarali bo'lsa-da, ayniqsa hisoblash talab qiladigan operatsiyalar bilan ishlaganda, unumdorlik oqibatlaridan xabardor bo'ling.
- Kodingizni hujjatlashtiring: Boshqa dasturchilarga ulardan qanday foydalanishni tushunishga yordam berish uchun generator funksiyalaringiz uchun aniq va qisqa hujjatlarni taqdim eting.
JavaScript'dan Tashqaridagi Qo'llanilish Holatlari
Generatorlar va iteratorlar tushunchasi JavaScript doirasidan tashqariga chiqadi va turli dasturlash tillari va stsenariylarida qo'llaniladi. Masalan:
- Python: Python JavaScript-ga juda o'xshash bo'lgan
yieldkalit so'zi yordamida generatorlarni o'rnatilgan holda qo'llab-quvvatlaydi. Ular ma'lumotlarni samarali qayta ishlash va xotirani boshqarish uchun keng qo'llaniladi. - C#: C# maxsus to'plam iteratsiyasini amalga oshirish uchun iteratorlar va
yield returniborasidan foydalanadi. - Ma'lumotlar Oqimi: Ma'lumotlarni qayta ishlash quvurlarida generatorlar katta ma'lumotlar oqimini qismlarga bo'lib qayta ishlash uchun ishlatilishi mumkin, bu samaradorlikni oshiradi va xotira sarfini kamaytiradi. Bu, ayniqsa, sensorlar, moliyaviy bozorlar yoki ijtimoiy tarmoqlardan real vaqtda olingan ma'lumotlar bilan ishlashda muhimdir.
- O'yin Yaratish: Generatorlar butun tarkibni oldindan hisoblamasdan va xotirada saqlamasdan, masalan, yer landshaftini yoki animatsiya ketma-ketliklarini yaratish kabi protsessual tarkibni yaratish uchun ishlatilishi mumkin.
Xulosa
JavaScript generator funksiyalari iteratorlarni yaratish va asinxron amallarni yanada nafis va samarali usulda bajarish uchun kuchli vositadir. Iterator protokolini tushunib, yield kalit so'zini o'zlashtirib, siz yanada o'qilishi oson, qo'llab-quvvatlanadigan va samarali JavaScript ilovalarini yaratish uchun generator funksiyalaridan foydalanishingiz mumkin. Sonlar ketma-ketligini yaratishdan tortib, murakkab ma'lumotlar tuzilmalarini aylanib chiqish va asinxron vazifalarni bajarishgacha, generator funksiyalari keng ko'lamli dasturlash muammolari uchun ko'p qirrali yechim taklif etadi. JavaScript ishlab chiqish jarayonida yangi imkoniyatlarni ochish uchun generator funksiyalarini qabul qiling.