JavaScript Iterator Protokolini tushunish va joriy etish bo'yicha to'liq qo'llanma, ma'lumotlarni yaxshiroq boshqarish uchun maxsus iteratorlar yaratish imkonini beradi.
JavaScript Iterator Protokoli va Maxsus Iteratorlarni Tushunish
JavaScript'ning Iterator Protokoli ma'lumotlar tuzilmalarini aylanib o'tishning standartlashtirilgan usulini taqdim etadi. Ushbu protokolni tushunish dasturchilarga massivlar va satrlar kabi o'rnatilgan iteratsiya qilinadiganlar bilan samarali ishlash hamda maxsus ma'lumotlar tuzilmalari va dastur talablariga moslashtirilgan o'zlarining maxsus iteratsiya qilinadiganlarini yaratish imkonini beradi. Ushbu qo'llanma Iterator Protokolini va maxsus iteratorlarni qanday joriy etishni to'liq o'rganib chiqadi.
Iterator Protokoli nima?
Iterator Protokoli obyektning qanday qilib iteratsiya qilinishini, ya'ni uning elementlariga ketma-ket qanday kirish mumkinligini belgilaydi. U ikki qismdan iborat: Iteratsiya qilinadigan (Iterable) protokoli va Iterator protokoli.
Iteratsiya qilinadigan (Iterable) Protokoli
Agar obyektda Symbol.iterator
kalitiga ega metod mavjud bo'lsa, u Iteratsiya qilinadigan (Iterable) hisoblanadi. Bu metod Iterator protokoliga mos keladigan obyektni qaytarishi kerak.
Mohiyatan, iteratsiya qilinadigan obyekt o'zi uchun iterator yaratishni biladi.
Iterator Protokoli
Iterator protokoli ketma-ketlikdan qiymatlarni qanday olishni belgilaydi. Agar obyektda ikkita xususiyatga ega obyektni qaytaruvchi next()
metodi mavjud bo'lsa, u iterator hisoblanadi:
value
: Ketma-ketlikdagi keyingi qiymat.done
: Iterator ketma-ketlikning oxiriga yetganligini ko'rsatuvchi mantiqiy (boolean) qiymat. Agardone
true
bo'lsa,value
xususiyatini yozmasa ham bo'ladi.
next()
metodi Iterator protokolining asosiy ishchi qismidir. next()
ga har bir murojaat iteratorni oldinga siljitadi va ketma-ketlikdagi keyingi qiymatni qaytaradi. Barcha qiymatlar qaytarilganda, next()
done
qiymati true
ga o'rnatilgan obyektni qaytaradi.
O'rnatilgan Iteratsiya Qilinadiganlar
JavaScript o'zida bir nechta o'rnatilgan, tabiiy ravishda iteratsiya qilinadigan ma'lumotlar tuzilmalarini taqdim etadi. Bularga quyidagilar kiradi:
- Massivlar
- Satrlar
- Maplar
- Setlar
- Funksiyaning Arguments obyekti
- TypedArrays
Ushbu iteratsiya qilinadiganlar for...of
tsikli, yoyish sintaksisi (...
) va Iterator Protokoliga tayanadigan boshqa konstruksiyalar bilan bevosita ishlatilishi mumkin.
Massivlar bilan misol:
const myArray = ["apple", "banana", "cherry"];
for (const item of myArray) {
console.log(item); // Chiqish: apple, banana, cherry
}
Satrlar bilan misol:
const myString = "Hello";
for (const char of myString) {
console.log(char); // Chiqish: H, e, l, l, o
}
for...of
Tsikli
for...of
tsikli iteratsiya qilinadigan obyektlarni aylanib chiqish uchun kuchli konstruksiyadir. U Iterator Protokolining murakkabliklarini avtomatik ravishda boshqaradi va ketma-ketlikdagi qiymatlarga kirishni osonlashtiradi.
for...of
tsiklining sintaksisi:
for (const element of iterable) {
// Har bir element uchun bajariladigan kod
}
for...of
tsikli iteratsiya qilinadigan obyektdan iteratorni oladi (Symbol.iterator
yordamida) va done
true
bo'lguncha iteratorning next()
metodini qayta-qayta chaqiradi. Har bir iteratsiyada element
o'zgaruvchisiga next()
tomonidan qaytarilgan value
xususiyati tayinlanadi.
Maxsus Iteratorlar Yaratish
JavaScript o'rnatilgan iteratsiya qilinadiganlarni taqdim etsa-da, Iterator Protokolining haqiqiy kuchi o'zingizning ma'lumotlar tuzilmalaringiz uchun maxsus iteratorlarni belgilash qobiliyatidadir. Bu sizning ma'lumotlaringizni qanday aylanib o'tishni va ularga qanday kirishni nazorat qilish imkonini beradi.
Maxsus iteratorni yaratish uchun quyidagi amallarni bajaring:
- Maxsus ma'lumotlar tuzilmangizni ifodalovchi sinf yoki obyektni aniqlang.
- Sinfingiz yoki obyektingizda
Symbol.iterator
metodini joriy eting. Bu metod iterator obyektini qaytarishi kerak. - Iterator obyekti
value
vadone
xususiyatlariga ega obyektni qaytaruvchinext()
metodiga ega bo'lishi kerak.
Misol: Oddiy Diapazon uchun Iterator Yaratish
Keling, sonlar diapazonini ifodalovchi Range
deb nomlangan sinf yaratamiz. Biz diapazondagi sonlarni iteratsiya qilish uchun Iterator Protokolini joriy qilamiz.
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
let currentValue = this.start;
const that = this; // Iterator obyekti ichida 'this' ni ishlatish uchun ushlab qolamiz
return {
next() {
if (currentValue <= that.end) {
return {
value: currentValue++,
done: false,
};
} else {
return {
value: undefined,
done: true,
};
}
},
};
}
}
const myRange = new Range(1, 5);
for (const number of myRange) {
console.log(number); // Chiqish: 1, 2, 3, 4, 5
}
Tushuntirish:
Range
sinfi o'z konstruktoridastart
vaend
qiymatlarini qabul qiladi.Symbol.iterator
metodi iterator obyektini qaytaradi. Bu iterator obyekti o'z holatiga (currentValue
) vanext()
metodiga ega.next()
metodicurrentValue
diapazon ichida ekanligini tekshiradi. Agar shunday bo'lsa, u joriy qiymat vadone
false
ga o'rnatilgan obyektni qaytaradi. Shuningdek, u keyingi iteratsiya uchuncurrentValue
ni oshiradi.currentValue
end
qiymatidan oshib ketganda,next()
metodidone
true
ga o'rnatilgan obyektni qaytaradi.that = this
ishlatilishiga e'tibor bering.next()
metodi boshqa bir doirada (for...of
tsikli tomonidan) chaqirilgani uchun,next()
ichidagi `this` `Range` obyektiga ishora qilmaydi. Bu muammoni hal qilish uchun biz `this` qiymatini (`Range` obyektini)next()
doirasidan tashqarida `that` o'zgaruvchisiga saqlab olamiz va keyin `that` ni `next()` ichida ishlatamiz.
Misol: Bog'langan Ro'yxat uchun Iterator Yaratish
Keling, yana bir misolni ko'rib chiqaylik: bog'langan ro'yxat ma'lumotlar tuzilmasi uchun iterator yaratish. Bog'langan ro'yxat - bu tugunlar ketma-ketligi bo'lib, har bir tugun qiymat va ro'yxatdagi keyingi tugunga havola (ko'rsatkich) saqlaydi. Ro'yxatdagi oxirgi tugun null (yoki undefined) ga ishora qiladi.
class LinkedListNode {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
}
class LinkedList {
constructor() {
this.head = null;
}
append(value) {
const newNode = new LinkedListNode(value);
if (!this.head) {
this.head = newNode;
return;
}
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
[Symbol.iterator]() {
let current = this.head;
return {
next() {
if (current) {
const value = current.value;
current = current.next;
return {
value: value,
done: false
};
} else {
return {
value: undefined,
done: true
};
}
}
};
}
}
// Ishlatish misoli:
const myList = new LinkedList();
myList.append("London");
myList.append("Paris");
myList.append("Tokyo");
for (const city of myList) {
console.log(city); // Chiqish: London, Paris, Tokyo
}
Tushuntirish:
LinkedListNode
sinfi bog'langan ro'yxatdagi bitta tugunni ifodalaydi, undavalue
va keyingi tugunga havola (next
) saqlanadi.LinkedList
sinfi bog'langan ro'yxatning o'zini ifodalaydi. U ro'yxatdagi birinchi tugunga ishora qiluvchihead
xususiyatiga ega.append()
metodi ro'yxatning oxiriga yangi tugunlar qo'shadi.Symbol.iterator
metodi iterator obyektini yaratadi va qaytaradi. Bu iterator tashrif buyurilayotgan joriy tugunni (current
) kuzatib boradi.next()
metodi joriy tugun mavjudligini tekshiradi (current
null emas). Agar mavjud bo'lsa, u joriy tugundan qiymatni oladi,current
ko'rsatkichini keyingi tugunga o'tkazadi va qiymat hamdadone: false
bilan obyektni qaytaradi.current
null bo'lganda (bu ro'yxat oxiriga yetganimizni bildiradi),next()
metodidone: true
bilan obyektni qaytaradi.
Generator Funksiyalari
Generator funksiyalari iteratorlarni yaratishning yanada ixcham va oqlangan usulini taqdim etadi. Ular talab bo'yicha qiymatlarni ishlab chiqarish uchun yield
kalit so'zidan foydalanadilar.
Generator funksiyasi function*
sintaksisi yordamida aniqlanadi.
Misol: Generator Funksiyasi yordamida Iterator Yaratish
Keling, Range
iteratorini generator funksiyasi yordamida qayta yozamiz:
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i <= this.end; i++) {
yield i;
}
}
}
const myRange = new Range(1, 5);
for (const number of myRange) {
console.log(number); // Chiqish: 1, 2, 3, 4, 5
}
Tushuntirish:
Symbol.iterator
metodi endi generator funksiyasi (*
belgisiga e'tibor bering).- Generator funksiyasi ichida biz sonlar diapazoni bo'ylab iteratsiya qilish uchun
for
tsiklidan foydalanamiz. yield
kalit so'zi generator funksiyasining bajarilishini to'xtatadi va joriy qiymatni (i
) qaytaradi. Iteratorningnext()
metodi keyingi safar chaqirilganda, bajarilish to'xtagan joydan (yield
dan keyin) davom etadi.- Tsikl tugagach, generator funksiyasi yashirin ravishda
{ value: undefined, done: true }
qaytaradi, bu iteratsiyaning tugaganligini bildiradi.
Generator funksiyalari next()
metodini va done
bayrog'ini avtomatik ravishda boshqarib, iterator yaratishni soddalashtiradi.
Misol: Fibonachchi Ketma-ketligi Generatori
Generator funksiyalaridan foydalanishning yana bir ajoyib misoli - Fibonachchi ketma-ketligini generatsiya qilish:
function* fibonacciSequence() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b]; // Bir vaqtning o'zida yangilash uchun destrukturizatsiya
}
}
const fibonacci = fibonacciSequence();
for (let i = 0; i < 10; i++) {
console.log(fibonacci.next().value); // Chiqish: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
}
Tushuntirish:
fibonacciSequence
funksiyasi generator funksiyasidir.- U Fibonachchi ketma-ketligidagi birinchi ikki songa (0 va 1) teng bo'lgan
a
vab
o'zgaruvchilarini ishga tushiradi. while (true)
tsikli cheksiz ketma-ketlik yaratadi.yield a
bayonotia
ning joriy qiymatini ishlab chiqaradi.[a, b] = [b, a + b]
bayonoti destrukturizatsiya yordamidaa
vab
ni ketma-ketlikdagi keyingi ikki songa bir vaqtda yangilaydi.fibonacci.next().value
ifodasi generatordan keyingi qiymatni oladi. Generator cheksiz bo'lgani uchun undan qancha qiymat olishni nazorat qilishingiz kerak. Bu misolda biz dastlabki 10 ta qiymatni olamiz.
Iterator Protokolidan Foydalanishning Afzalliklari
- Standartlashtirish: Iterator Protokoli turli xil ma'lumotlar tuzilmalarini iteratsiya qilishning izchil usulini taqdim etadi.
- Moslashuvchanlik: Siz o'zingizning maxsus ehtiyojlaringizga moslashtirilgan maxsus iteratorlarni aniqlashingiz mumkin.
- O'qilishi oson:
for...of
tsikli iteratsiya kodini o'qilishi oson va ixcham qiladi. - Samaradorlik: Iteratorlar 'dangasa' bo'lishi mumkin, ya'ni ular qiymatlarni faqat kerak bo'lganda generatsiya qiladi, bu katta ma'lumotlar to'plamlari uchun samaradorlikni oshirishi mumkin. Masalan, yuqoridagi Fibonachchi ketma-ketligi generatori faqat `next()` chaqirilganda keyingi qiymatni hisoblaydi.
- Muvofiqlik: Iteratorlar spread sintaksisi va destrukturizatsiya kabi boshqa JavaScript xususiyatlari bilan uzluksiz ishlaydi.
Iteratorlarning Ilg'or Texnikalari
Iteratorlarni Birlashtirish
Siz bir nechta iteratorni bitta iteratorga birlashtirishingiz mumkin. Bu bir nechta manbadan olingan ma'lumotlarni yagona usulda qayta ishlash kerak bo'lganda foydalidir.
function* combineIterators(...iterables) {
for (const iterable of iterables) {
for (const item of iterable) {
yield item;
}
}
}
const array1 = [1, 2, 3];
const array2 = ["a", "b", "c"];
const string1 = "XYZ";
const combined = combineIterators(array1, array2, string1);
for (const value of combined) {
console.log(value); // Chiqish: 1, 2, 3, a, b, c, X, Y, Z
}
Ushbu misolda `combineIterators` funksiyasi argument sifatida istalgan miqdordagi iteratsiya qilinadiganlarni qabul qiladi. U har bir iteratsiya qilinadiganni aylanib chiqadi va har bir elementni qaytaradi. Natijada barcha kiruvchi iteratsiya qilinadiganlardan olingan barcha qiymatlarni ishlab chiqaradigan yagona iterator hosil bo'ladi.
Iteratorlarni Filtrlash va O'zgartirish
Siz boshqa iterator tomonidan ishlab chiqarilgan qiymatlarni filtrlash yoki o'zgartiradigan iteratorlar ham yaratishingiz mumkin. Bu ma'lumotlarni quvur shaklida qayta ishlashga imkon beradi, bunda har bir qiymat generatsiya qilinishi bilan unga turli operatsiyalar qo'llaniladi.
function* filterIterator(iterable, predicate) {
for (const item of iterable) {
if (predicate(item)) {
yield item;
}
}
}
function* mapIterator(iterable, transform) {
for (const item of iterable) {
yield transform(item);
}
}
const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = filterIterator(numbers, (x) => x % 2 === 0);
const squaredEvenNumbers = mapIterator(evenNumbers, (x) => x * x);
for (const value of squaredEvenNumbers) {
console.log(value); // Chiqish: 4, 16, 36
}
Bu yerda `filterIterator` iteratsiya qilinadigan va predikat funksiyasini qabul qiladi. U faqat predikat `true` qaytargan elementlarni qaytaradi. `mapIterator` esa iteratsiya qilinadigan va o'zgartirish funksiyasini qabul qiladi. U har bir elementga o'zgartirish funksiyasini qo'llash natijasini qaytaradi.
Haqiqiy Hayotdagi Qo'llanilishlar
Iterator Protokoli JavaScript kutubxonalari va freymvorklarida keng qo'llaniladi va u turli xil haqiqiy hayotiy dasturlarda, ayniqsa katta hajmdagi ma'lumotlar to'plamlari yoki asinxron operatsiyalar bilan ishlashda qimmatlidir.
- Ma'lumotlarni qayta ishlash: Iteratorlar katta ma'lumotlar to'plamlarini samarali qayta ishlash uchun foydalidir, chunki ular butun ma'lumotlar to'plamini xotiraga yuklamasdan ma'lumotlar bilan qismlarga bo'lib ishlash imkonini beradi. Mijozlar ma'lumotlarini o'z ichiga olgan katta CSV faylini tahlil qilishni tasavvur qiling. Iterator butun faylni bir vaqtning o'zida xotiraga yuklamasdan har bir qatorni qayta ishlashga imkon beradi.
- Asinxron operatsiyalar: Iteratorlar API'dan ma'lumotlarni olish kabi asinxron operatsiyalarni boshqarish uchun ishlatilishi mumkin. Siz generator funksiyalaridan ma'lumotlar mavjud bo'lguncha bajarilishni to'xtatib turish va keyin keyingi qiymat bilan davom etish uchun foydalanishingiz mumkin.
- Maxsus ma'lumotlar tuzilmalari: Iteratorlar maxsus aylanib o'tish talablariga ega bo'lgan maxsus ma'lumotlar tuzilmalarini yaratish uchun zarurdir. Daraxt ma'lumotlar tuzilmasini ko'rib chiqing. Siz daraxtni ma'lum bir tartibda (masalan, chuqurlik bo'yicha yoki kenglik bo'yicha) aylanib chiqish uchun maxsus iteratorni joriy etishingiz mumkin.
- O'yin ishlab chiqish: O'yin ishlab chiqishda iteratorlar o'yin obyektlari, zarrachalar effektlari va boshqa dinamik elementlarni boshqarish uchun ishlatilishi mumkin.
- Foydalanuvchi interfeysi kutubxonalari: Ko'pgina UI kutubxonalari asosiy ma'lumotlar o'zgarishlariga asoslanib komponentlarni samarali yangilash va render qilish uchun iteratorlardan foydalanadi.
Eng Yaxshi Amaliyotlar
Symbol.iterator
ni to'g'ri joriy eting:Symbol.iterator
metodining Iterator Protokoliga mos keladigan iterator obyektini qaytarishiga ishonch hosil qiling.done
bayrog'ini aniq boshqaring:done
bayrog'i iteratsiyaning tugaganligini bildirish uchun juda muhim. Uninext()
metodida to'g'ri o'rnatganingizga ishonch hosil qiling.- Generator funksiyalaridan foydalanishni ko'rib chiqing: Generator funksiyalari iteratorlarni yaratishning yanada ixcham va o'qilishi oson usulini taqdim etadi.
next()
da yon ta'sirlardan saqlaning:next()
metodi asosan keyingi qiymatni olish va iterator holatini yangilashga qaratilishi kerak.next()
ichida murakkab operatsiyalarni bajarish yoki yon ta'sirlardan saqlaning.- Iteratorlaringizni puxta sinovdan o'tkazing: Maxsus iteratorlaringizni turli xil ma'lumotlar to'plamlari va stsenariylar bilan sinab ko'ring, ularning to'g'ri ishlashiga ishonch hosil qiling.
Xulosa
JavaScript Iterator Protokoli ma'lumotlar tuzilmalarini aylanib o'tishning kuchli va moslashuvchan usulini taqdim etadi. Iteratsiya qilinadigan va Iterator protokollarini tushunib, generator funksiyalaridan foydalangan holda, siz o'zingizning maxsus ehtiyojlaringizga moslashtirilgan maxsus iteratorlarni yaratishingiz mumkin. Bu sizga ma'lumotlar bilan samarali ishlash, kodning o'qilishini yaxshilash va dasturlaringizning samaradorligini oshirish imkonini beradi. Iteratorlarni o'zlashtirish JavaScript imkoniyatlarini chuqurroq tushunishga yordam beradi va sizga yanada oqlangan va samarali kod yozish imkonini beradi.