Mundarija (31)
- Bu darsda
- 1. Nega bu kerak?
- 2. Eslab olamiz: callback va HOF
- 3. Callback imzosi: (element, index, array)
- 3.1 Kichik tajriba
- 3.2 Imzo nima?
- 3.3 Metod ichida nima bo'lyapti?
- 3.4 Kerakli parametrni olish
- 3.5 Uchinchi parametr qachon kerak?
- 4. HOF metodlar oilasi
- 4.1 Bitta imzo, har xil vazifa
- 4.2 Qaysi metodni tanlash kerak?
- 5. Metodning ikkinchi argumenti: thisArg
- 6. Callback ichida nimani o'zgartirmaslik kerak
- 6.1 Aylanayotgan massivni o'zgartirish
- 6.2 Elementning ichini o'zgartirish
- 6.3 Qoida: callback "so'raydi", o'zgartirmaydi
- 7. Deklarativ uslub
- 8. Ko'p uchraydigan xatolar
- 8.1 Callback o'rniga chaqiruv natijasini berish
- 8.2 Ikkinchi parametrga boshqa narsa kutish
- 8.3 Jingalak qavsli callback'da return yo'q
- 8.4 Aylanayotgan massivni o'zgartirish
- 9. Mashqlar
- 1-mashq (oson): Raqamlangan menyu
- 2-mashq (o'rta): Navbatda kim kimdan keyin
- 3-mashq (qiyin): O'zingizning findIndex
- 4-mashq: Vazifalar qadami — refaktoringni boshlaymiz
- 10. Real ishda
- Xulosa
- Manbalar
JavaScript massiv metodlari: callback imzosi va HOF metodlar oilasi
Qisqacha:
forEach,map,filter,find,somekabi massiv metodlari — tayyor HOF'lar: sikl ular ichida yashiringan, siz faqat callback berasiz. Har biri callback'ni har element uchun bir xil tartibda chaqiradi:(element, index, array)— element, uning indeksi va butun massiv. Callback faqat "so'rasin": aylanayotgan massivni va uning obyektlarini o'zgartirmasin.
Bu darsda
- Massiv metodi callback'ni qanday argumentlar bilan chaqirishini — callback imzosini — tushuntira olasiz.
- Callback'ning ikkinchi va uchinchi parametridan foydalana olasiz.
- Qaysi vazifaga qaysi HOF metod kerakligini tanlay olasiz.
- Callback ichida nimani o'zgartirib bo'lmasligini va nega shundayligini bilasiz.
vazifalarilovasining kodini uning ishini o'zgartirmay yaxshilashni boshlaysiz: birinchi siklniforEachga almashtirasiz.
Oldin bilishingiz kerak: Callback va HOF, Massiv bo'ylab yurish, Massivda qidirish va tekshirish, Havola semantikasi, Yakuniy loyiha: vazifalar ro'yxati.
1. Nega bu kerak?
09-qismda JavaScript brauzerga chiqdi: tugmalar, formalar, jonli ro'yxat. Qism oxirida vazifalar ilovasini yozdingiz. Endi 10-qism — "JavaScript chuqur". Bu qismda yana tilning o'ziga qaytamiz: massiv metodlari, obyektlar, closure, klasslar, xatolar va modullar. Bu nomlarning ko'pi hozir notanish — xavotir olmang, har birini o'z darsida noldan tushuntiramiz. Ko'p misollar yana Node konsolida bo'ladi, lekin har dars oxirida vazifalar bir qadam yaxshilanadi.
vazifalar.js ni oching. Unda ikki funksiya yonma-yon turibdi:
function korinadiganlar() {
const natija = [];
for (const vazifa of holat.vazifalar) {
if (mosmi(vazifa, holat.filtr)) {
natija.push(vazifa);
}
}
return natija;
}
function vazifaniTop(id) {
return holat.vazifalar.find((v) => v.id === id);
}Ikkalasi ham massiv bo'ylab yuradi va shartni tekshiradi. Lekin birinchisi 8 qator, ikkinchisi — bitta. Farq qayerda?
vazifaniTop da sikl yo'q. U find ichida yashiringan. Biz faqat "nimani qidiryapmiz" deb aytdik — (v) => v.id === id. "Bo'sh massiv yarat", "har birini aylan", "mos kelsa qo'sh" kabi qadamlarni find o'zi bajardi.
09-qismda korinadiganlar ni ataylab for...of bilan yozgan edik: Yakuniy loyiha darsida "massivning filter metodini 10-qismda o'rganamiz" degan edik. Shu va'dani bajarish vaqti keldi. Lekin avval bitta umumiy savolga javob beramiz: bunday metodlar callback'ni qanday chaqiradi? Bu — barcha keyingi darslarning kaliti.
2. Eslab olamiz: callback va HOF
Callback va HOF darsida ikki atamani o'rgangan edik:
- Callback — boshqa funksiyaga argument sifatida beriladigan funksiya. U qavssiz beriladi:
takrorla(3, salomBer). - HOF (yuqori tartibli funksiya) — funksiya qabul qiladigan yoki qaytaradigan funksiya.
Callback'ni qachon, necha marta va qanday qiymatlar bilan chaqirishni HOF hal qiladi. Siz faqat "nima qilish kerak" degan qismini berasiz.
Massiv bo'ylab yurish darsida forEach ni ko'rdik. U massivga "yopishtirilgan" tayyor HOF: sikl uning ichida, callback esa sizdan. Bugungi dars aynan shu metodlar oilasi haqida.
Tekshirib ko'ring:
narxlar.find((n) => n > 30000)ifodasida qaysi biri HOF, qaysi biri callback?
Javob
find — HOF: u funksiya qabul qiladi va uni o'zi chaqiradi. (n) => n > 30000 — callback: u argument sifatida berilgan. Necha marta chaqirilishini find hal qiladi — mos element topilishi bilan to'xtaydi.
3. Callback imzosi: (element, index, array)
3.1 Kichik tajriba
Keling, forEach ga callback sifatida console.log ning o'zini beramiz. U nechta argument olsa, hammasini bitta qatorga chiqaradi:
["osh", "manti"].forEach(console.log);Konsolda:
osh 0 [ 'osh', 'manti' ]
manti 1 [ 'osh', 'manti' ]Ajoyib! Har qatorda uchta qiymat. forEach har safar callback'ga element, uning indeksi va butun massivni bergan. Biz odatda faqat birinchisini olamiz, shuning uchun qolgan ikkitasini ko'rmay yurgan edik.
3.2 Imzo nima?
Imzo (signature) — funksiya qaysi parametrlarni qaysi tartibda olishining tavsifi. Massiv metodlarining callback imzosi bitta:
| O'rni | Nima keladi | Odatdagi nomi |
|---|---|---|
| 1-parametr | Joriy element | element, taom, vazifa |
| 2-parametr | Uning indeksi | index, i |
| 3-parametr | Butun massiv | array, hammasi |
Hayotdan o'xshatish: bank kvitansiyasi. Unda maydonlar tartibi qat'iy: avval ism, keyin summa, keyin sana. Kassir doim shu tartibda o'qiydi. Siz faqat kerakli maydonni to'ldirasiz, lekin "summa"ni "ism" joyiga yoza olmaysiz.
Callback'da ham shunday. Parametr nomlari — sizning ixtiyoringizda. Tartib esa o'zgarmaydi: birinchi parametrga doim element tushadi, ikkinchisiga — indeks.
3.3 Metod ichida nima bo'lyapti?
Buni o'z ko'zimiz bilan ko'rish uchun forEach ning soddalashtirilgan nusxasini o'zimiz yozamiz. U callback'ni aynan haqiqiy metod kabi — uchta argument bilan chaqiradi:
function harBirigaQil(massiv, amal) {
for (let i = 0; i < massiv.length; i++) {
amal(massiv[i], i, massiv);
}
}
const taomlar = ["osh", "manti"];
harBirigaQil(taomlar, (taom, indeks, hammasi) => {
console.log(`${indeks + 1}/${hammasi.length}: ${taom}`);
});Konsolda:
1/2: osh
2/2: mantiEndi qadamma-qadam yuring. Keyingi tugmasini bosib, amal(massiv[i], i, massiv) qatoridagi uchta qiymat callback'ning qaysi parametriga tushishini kuzating:
forEach, map, filter, find, some va boshqalar ichida aynan shunday sikl bor. Ularning har biri callback'ni (element, index, array) bilan chaqiradi. Farq — callback qaytargan qiymat bilan nima qilishida. Buni «HOF metodlar oilasi» bo'limida ko'ramiz.
O'zingiz to'ldiring. ["a", "b", "c"].forEach((x, i) => ...) da uchinchi chaqiruvda i ning qiymati — [:2], x niki esa — [:c].
3.4 Kerakli parametrni olish
Callback faqat kerakli parametrlarni oladi. Lekin tartib tufayli bitta qoida bor: ikkinchisi kerak bo'lsa, birinchisini ham yozish shart.
const navbat = ["Ali", "Malika", "Jasur"];
navbat.forEach((_, i) => {
console.log(`${i + 1}-o'rin band`);
});Konsolda:
1-o'rin band
2-o'rin band
3-o'rin bandBu yerda elementning o'zi kerak emas. Lekin i ikkinchi o'rinda turibdi, shuning uchun birinchi o'ringa nimadir yozish kerak. Dasturchilar bunday ishlatilmaydigan parametrni _ (pastki chiziq) deb nomlaydi. Bu JavaScript qoidasi emas, kelishuv: "bu parametr ataylab ishlatilmayapti".
3.5 Uchinchi parametr qachon kerak?
Uchinchi parametr — butun massiv — kamdan-kam kerak bo'ladi. Eng tipik holat: joriy elementni qo'shnisi bilan solishtirish.
Jasur aka «Bahor»ning haftalik tushumini kuzatadi. Har kun oldingi kundan ko'pmi yoki kammi?
const tushum = [1200000, 1500000, 1350000, 1800000];
tushum.forEach((summa, i, hammasi) => {
if (i === 0) {
console.log(`1-kun: ${summa}`);
return;
}
const farq = summa - hammasi[i - 1];
const belgi = farq > 0 ? "o'sdi" : "kamaydi";
console.log(`${i + 1}-kun: ${summa} (${belgi})`);
});Konsolda:
1-kun: 1200000
2-kun: 1500000 (o'sdi)
3-kun: 1350000 (kamaydi)
4-kun: 1800000 (o'sdi)hammasi[i - 1] — oldingi kunning tushumi. Callback tashqaridagi tushum nomini ham ishlatishi mumkin edi. Lekin uchinchi parametr callback'ni mustaqil qiladi: uni istalgan massivga, hatto nomi yo'q massivga ham bera olasiz. Birinchi kunda oldingi kun yo'q — shuning uchun erta qaytish bilan alohida chiqardik.
Tekshirib ko'ring:
[10, 20, 30].forEach((a, b, c) => console.log(c.length - b));nima chiqaradi?
Javob
3, 2, 1. Nomlar g'alati bo'lsa ham, tartib hal qiladi: a — element, b — indeks, c — massiv. c.length doim 3, b esa 0, 1, 2. Parametr nomi ma'no bermaydi — o'rni beradi.
4. HOF metodlar oilasi
4.1 Bitta imzo, har xil vazifa
Massivning callback oladigan metodlari ko'p. Ularning bir qismini 08-qismda o'rgandingiz, qolganlari shu qismda keladi:
| Metod | Callback qaytargani | Metod qaytaradi |
|---|---|---|
forEach |
e'tiborga olinmaydi | undefined |
find, findIndex |
true/false |
element yoki indeks |
some, every |
true/false |
true yoki false |
map |
yangi element | yangi massiv |
filter |
true/false |
yangi massiv |
reduce |
yangi akkumulyator | istalgan qiymat |
Hammasi callback'ni (element, index, array) bilan chaqiradi. Ikki istisno bor. reduce ga oldin yana bitta qiymat — "akkumulyator", ya'ni hozirgacha yig'ilgan natija — beriladi, uni reduce darsida ko'ramiz. Saralash metodi sort esa ikki elementni solishtiradi: (a, b) — sort darsi.
Farq jadvalning o'rta ustunida: callback nima qaytarishi va metod shu qiymat bilan nima qilishi. Bir xil callback'ni har xil metodga bering:
const narxlar = [28000, 35000, 5000];
const qimmatmi = (narx) => narx > 30000;
console.log(narxlar.find(qimmatmi)); // 35000
console.log(narxlar.findIndex(qimmatmi)); // 1
console.log(narxlar.some(qimmatmi)); // true
console.log(narxlar.every(qimmatmi)); // false
console.log(narxlar.forEach(qimmatmi)); // undefinedCallback bitta — qimmatmi. U har safar true yoki false qaytaradi. find birinchi true bergan elementni oldi, findIndex — uning indeksini. some "kamida bittasi truemi?" deb so'radi, every — "hammasimi?". forEach esa javoblarni tashlab yubordi.
Callback nomi ham qiziq: qimmatmi. U savolga javob beradi, shuning uchun nomi savol shaklida — o'zbek tilidagi "-mi" qo'shimchasi bilan. 09-qismdagi mosmi ham shunday.
4.2 Qaysi metodni tanlash kerak?
Metodni tanlash uchun o'zingizga bitta savol bering: "massivdan nima olmoqchiman?" Sxemadagi strelka yozuvlarini o'qing — har biri bitta javob:
flowchart TD
S{"Massivdan nima kerak?"}
S -- "har biri bilan ish" --> FE["forEach → undefined"]
S -- "har birini aylantirish" --> MAP["map → yangi massiv"]
S -- "ba'zilarini tanlash" --> FIL["filter → yangi massiv"]
S -- "bitta elementni topish" --> FIND["find → element"]
S -- "ha yoki yo'q" --> SOME["some / every → boolean"]
S -- "bitta qiymatga yig'ish" --> RED["reduce → istalgan qiymat"]map, filter va reduce — keyingi uch darsning mavzusi. Hozircha nomlarini va qaysi savolga javob berishini eslab qoling.
Maslahat: Bu metodlarning ko'pi JavaScript'ga 2009-yilda (ES5 standarti) qo'shilgan:
forEach,map,filter,some,every,reduce.findvafindIndex— 2015-yilda (ES2015),findLast— 2023-yilda. Hammasi barcha zamonaviy brauzer va Node'da ishlaydi.
Tekshirib ko'ring: "Savatda 50 000 so'mdan qimmat mahsulot bormi?" Bu savolga qaysi metod javob beradi va u nima qaytaradi?
Javob
some — true yoki false qaytaradi. Savol "bormi?" — demak ha yoki yo'q. find ham ishlaydi, lekin u mahsulotning o'zini qaytaradi. Bizga mahsulot emas, faqat javob kerak.
5. Metodning ikkinchi argumenti: thisArg
Callback'dan keyin metodga yana bitta argument berish mumkin:
massiv.forEach(callback, thisArg);Ikkinchi argument callback'ga uzatilmaydi. U callback ichidagi this degan maxsus so'z nimaga qarashini belgilaydi. this ni this: to'rt qoida darsida o'rganamiz — hozir bilish shart emas. Arrow funksiyada thisArg umuman ta'sir qilmaydi. Zamonaviy kodda u deyarli uchramaydi, lekin eski kodda ko'rsangiz, tanib oling.
Bu argumentni bilishning foydasi boshqa joyda. Boshlovchilar ba'zan ikkinchi argumentni "callback'ga qo'shimcha ma'lumot" deb o'ylaydi:
function chiqar(narx, birlik) {
console.log(narx, birlik);
}
[35000, 28000].forEach(chiqar, "so'm");Konsolda:
35000 0
28000 1"so'm" o'rniga 0 va 1 chiqdi. Ikki xato bir vaqtda bo'ldi. Birinchisi: "so'm" thisArg ga ketdi, callback uni olmadi. Ikkinchisi: birlik — callback'ning ikkinchi parametri, unga esa doim indeks tushadi.
Tuzatish — Callback va HOF darsidagi usul: callback'ni arrow funksiyaga o'rab, argumentni o'zingiz bering.
function chiqar(narx, birlik) {
console.log(narx, birlik);
}
[35000, 28000].forEach((narx) => chiqar(narx, "so'm"));Konsolda:
35000 so'm
28000 so'mQoida: tayyor funksiyani metodga to'g'ridan-to'g'ri berishdan oldin uning parametrlariga qarang. Ikkinchi parametri bo'lsa, unga indeks tushadi. Kerakli narsa tushmasa — arrow bilan o'rang.
6. Callback ichida nimani o'zgartirmaslik kerak
HOF metod callback'dan javob kutadi. Callback esa ba'zan "javob berish" bilan birga yana nimanidir o'zgartirib yuboradi. Bu ikki xil tuzoqqa olib keladi.
6.1 Aylanayotgan massivni o'zgartirish
Massiv bo'ylab yurish darsida for sikli ichida splice qilganda bitta "sut" qolib ketgan edi. forEach da ham xuddi shunday:
const savat = ["sut", "sut", "non", "sut"];
savat.forEach((mahsulot, i) => {
if (mahsulot === "sut") {
savat.splice(i, 1);
}
});
console.log(savat); // [ 'sut', 'non' ]Sabab o'sha: forEach ichida ham oddiy indeksli sikl ishlaydi. Element o'chganda qolganlar chapga suriladi, sikl esa keyingi indeksga o'tib ketadi.
Qo'shish ham kutilmagan natija beradi:
const raqamlar = [1, 2, 3];
raqamlar.forEach((r) => {
raqamlar.push(r * 10);
});
console.log(raqamlar); // [ 1, 2, 3, 10, 20, 30 ]Cheksiz sikl bo'lmadi. Metod boshlanishida massiv uzunligini eslab qoladi va faqat shuncha elementni aylanadi. Yangi qo'shilganlar ko'rilmaydi. Bunday kodni o'qigan odam xulqni oldindan aytib bera olmaydi — shuning uchun qoida qat'iy: callback ichida aylanayotgan massivga push, splice, pop qilmang. Massivdan elementlarni olib tashlashning xavfsiz yo'li — filter, uni ikki darsdan keyin ko'ramiz.
6.2 Elementning ichini o'zgartirish
Massivda obyektlar bo'lsa, callback har obyektning havolasini oladi. Havola semantikasi darsini eslang: havola orqali o'zgartirsangiz, asl obyekt o'zgaradi. Qiymatni yangisini yasamay, joyida o'zgartirish mutatsiya deyiladi (Element qo'shish va olib tashlash darsidagi atama).
Otabek kechki aksiya uchun narxlarni 10% arzonroq ko'rsatmoqchi:
const menyu = [
{ nom: "Osh", narx: 35000 },
{ nom: "Manti", narx: 30000 },
];
menyu.forEach((taom) => {
taom.narx = taom.narx - taom.narx / 10;
console.log(`${taom.nom}: ${taom.narx}`);
});
console.log(menyu[0].narx); // 31500Konsolda:
Osh: 31500
Manti: 27000
31500Aksiya narxlari to'g'ri chiqdi. Lekin oxirgi qatorga qarang: asl menyuda ham osh endi 31 500. Ertalab kassa shu menyudan narx olsa, mijozlar chegirmani tekinga oladi. Callback "ko'rsatish" o'rniga ma'lumotni buzdi.
To'g'risi — yangi qiymatni alohida o'zgaruvchida hisoblash:
const menyu = [
{ nom: "Osh", narx: 35000 },
{ nom: "Manti", narx: 30000 },
];
menyu.forEach((taom) => {
const aksiyaNarxi = taom.narx - taom.narx / 10;
console.log(`${taom.nom}: ${aksiyaNarxi}`);
});
console.log(menyu[0].narx); // 35000Konsolda:
Osh: 31500
Manti: 27000
35000Menyu buzilmadi. Aksiya narxlari bilan yangi massiv kerak bo'lsa — buni keyingi darsdagi map qiladi.
6.3 Qoida: callback "so'raydi", o'zgartirmaydi
Pure funksiya darsini eslang: toza funksiya natija qaytaradi va tashqi dunyoni o'zgartirmaydi. find, some, every, map, filter, reduce ga beriladigan callback toza bo'lsin. U faqat qaraydi va javob qaytaradi.
Yagona istisno — forEach. Uning callback'i hech narsa qaytarmaydi, demak uning butun vazifasi — yon ta'sir: konsolga chiqarish, DOM'ni o'zgartirish, xabar yuborish. Lekin forEach da ham aylanayotgan massivning o'zini o'zgartirmang.
Diqqat:
vazifalardagivazifaniAlmashtirfunksiyasiholatni o'zgartiradi — bu boshqa narsa. U callback emas, balki holatni ataylab o'zgartiradigan funksiya (Holatdan UI chizish qolipi). Qoida faqat massiv metodlariga beriladigan callback'lar haqida.
Tekshirib ko'ring:
const topildi = menyu.find((t) => t.nom === "Osh"); topildi.narx = 0;— aslmenyuo'zgaradimi?
Javob
Ha. find obyektning nusxasini emas, o'zini — havolasini — qaytaradi. topildi va menyu[0] bitta obyektga qaraydi. topildi.narx = 0 — mutatsiya, uni menyu ham ko'radi.
7. Deklarativ uslub
Holatdan UI chizish darsida ikki yondashuvni ko'rgan edik. Imperativ — har qadamni aytasiz: "to'g'riga yur, chapga buril". Deklarativ — natijani aytasiz: "Chilonzor, 9-kvartal", yo'lni esa navigator topadi.
for...of sikli — imperativ. Siz kompyuterga har qadamni aytasiz: bo'sh massiv yarat, har elementni ol, shartni tekshir, mos kelsa qo'sh, oxirida qaytar. HOF metod — deklarativ: siz faqat nima kerakligini aytasiz.
Bir xil vazifa — ikki uslubda. Faol vazifalar sonini sanaymiz:
const vazifalar = [
{ id: 1, matn: "Non olish", bajarildi: false },
{ id: 2, matn: "DOM darsini takrorlash", bajarildi: true },
{ id: 3, matn: "Onamga qo'ng'iroq qilish", bajarildi: false },
];
// Imperativ: har qadam qo'lda
let soni = 0;
for (const vazifa of vazifalar) {
if (!vazifa.bajarildi) {
soni++;
}
}
console.log(soni); // 2
// Deklarativ: "bajarilmaganlarni tanla, sonini ol"
const faollar = vazifalar.filter((v) => !v.bajarildi);
console.log(faollar.length); // 2Ikkinchi yozuvdagi filter — shartga mos elementlardan yangi massiv yasaydi. Uni filter darsida to'liq o'rganamiz, hozir faqat o'qilishiga qarang. Deklarativ kodning foydalari:
- Niyat nomda.
filterso'zini ko'rgan odam darhol tushunadi: tanlash bo'lyapti. Sikl ichini o'qib, buni topish shart emas. - Xato uchun joy kam.
pushni unutish,<=bilan chegaradan chiqish, noto'g'ri indeks — bularning hammasi metod ichida, u esa sinalgan. - O'zgaruvchan "qutilar" yo'q.
let soniyoki bo'shnatijamassivi kerak emas. Natija bitta ifodadan chiqadi.
Lekin for...of eskirmadi. U hamon yaxshiroq tanlov bo'lgan holatlar bor. Masalan, siklni o'rtada break bilan to'xtatish kerak bo'lsa — forEach buni qila olmaydi (Massiv bo'ylab yurish). Juda katta ma'lumotda ketma-ket bir necha metod chaqirish sekinlashishi ham mumkin — buni Metod zanjiri darsida o'lchaymiz.
Tekshirib ko'ring:
navbat.some((ism) => ism === "Malika")— imperativ yoki deklarativ yozuvmi? Nega?
Javob
Deklarativ. Unda faqat savol bor: "Malika bormi?" Massivni aylanish, har ismni olish va topganda to'xtash — some ning ichida. Imperativ variantda bu qadamlarni for...of, if va break bilan o'zingiz yozardingiz.
8. Ko'p uchraydigan xatolar
8.1 Callback o'rniga chaqiruv natijasini berish
function chiqar(taom) {
console.log(taom);
}
["osh", "manti"].forEach(chiqar());Avval undefined chiqadi, keyin xato:
TypeError: undefined is not a functionTarjimasi: "undefined — funksiya emas". chiqar() qavs bilan yozildi va darhol, argumentsiz chaqirildi — shuning uchun konsolda undefined. Uning natijasi ham undefined edi, forEach esa shu undefined ni chaqirmoqchi bo'ldi. Tuzatish: qavssiz — forEach(chiqar).
8.2 Ikkinchi parametrga boshqa narsa kutish
«Metodning ikkinchi argumenti» bo'limidagi chiqar(narx, birlik) — shu xato. Tayyor funksiyani to'g'ridan-to'g'ri bersangiz, uning ikkinchi parametriga indeks, uchinchisiga massiv tushadi. Funksiya ular bilan boshqa ish qilsa — natija buziladi, ko'pincha xatosiz. Bunday xatoning eng mashhur namunasi — ["1", "2", "3"].map(parseInt) — keyingi darsda.
8.3 Jingalak qavsli callback'da return yo'q
const narxlar = [28000, 35000];
const topildi = narxlar.find((narx) => {
narx > 30000;
});
console.log(topildi); // undefinedJingalak qavs ochildi — yashirin return ishlamaydi. Callback har safar undefined qaytardi, find uchun bu "mos emas". Tuzatish: (narx) => narx > 30000 yoki qavs ichida return narx > 30000;.
8.4 Aylanayotgan massivni o'zgartirish
«Callback ichida nimani o'zgartirmaslik kerak» bo'limidagi ikki misol. Xato xabari chiqmaydi — shuning uchun bu xato xavfli. Tuzatish: yangi massiv yasang (filter, map), aslini esa o'z holiga qo'ying.
9. Mashqlar
1-mashq (oson): Raqamlangan menyu
menyu massividan forEach bilan raqamlangan ro'yxat chiqaring. Raqam — indeksdan bitta ko'p.
const menyu = ["Osh", "Lag'mon", "Manti", "Ko'k choy"];Natija to'rt qator bo'lsin: birinchisi 1. Osh, oxirgisi 4. Ko'k choy.
Yechim
const menyu = ["Osh", "Lag'mon", "Manti", "Ko'k choy"];
menyu.forEach((taom, i) => {
console.log(`${i + 1}. ${taom}`);
});Konsolda:
1. Osh
2. Lag'mon
3. Manti
4. Ko'k choyIndeks callback'ning ikkinchi parametri. U 0 dan boshlanadi, shuning uchun i + 1.
2-mashq (o'rta): Navbatda kim kimdan keyin
Navbatdagi mijozlar ro'yxati berilgan. forEach bilan har mijoz uchun Malika — Ali dan keyin ko'rinishidagi qatorni chiqaring. Birinchi mijoz uchun Ali — navbat boshida.
Ishora: callback'ning uchinchi parametri — butun massiv. Oldingi mijoz — hammasi[i - 1].
const navbat = ["Ali", "Malika", "Bobur"];Yechim
const navbat = ["Ali", "Malika", "Bobur"];
navbat.forEach((ism, i, hammasi) => {
if (i === 0) {
console.log(`${ism} — navbat boshida`);
return;
}
console.log(`${ism} — ${hammasi[i - 1]} dan keyin`);
});Konsolda:
Ali — navbat boshida
Malika — Ali dan keyin
Bobur — Malika dan keyinreturn faqat shu chaqiruvni tugatadi — forEach keyingi elementga o'tadi (Massiv bo'ylab yurish).
3-mashq (qiyin): O'zingizning findIndex
birinchiIndeks(massiv, shart) funksiyasini yozing. U haqiqiy findIndex kabi ishlasin:
shartcallback'ini har element uchun(element, index, array)bilan chaqirsin;- birinchi
truebergan elementning indeksini qaytarsin va to'xtasin; - hech biri mos kelmasa —
-1.
So'ng uni haqiqiy findIndex bilan uchta shartda solishtiring.
Yechim
function birinchiIndeks(massiv, shart) {
for (let i = 0; i < massiv.length; i++) {
if (shart(massiv[i], i, massiv)) {
return i;
}
}
return -1;
}
const narxlar = [5000, 35000, 28000, 35000];
const qimmatmi = (n) => n > 30000;
const ikkinchiOsh = (n, i) => n === 35000 && i > 1;
const juda = (n) => n > 100000;
console.log(birinchiIndeks(narxlar, qimmatmi)); // 1
console.log(narxlar.findIndex(qimmatmi)); // 1
console.log(birinchiIndeks(narxlar, ikkinchiOsh)); // 3
console.log(narxlar.findIndex(ikkinchiOsh)); // 3
console.log(birinchiIndeks(narxlar, juda)); // -1
console.log(narxlar.findIndex(juda)); // -1return i siklni ham, funksiyani ham to'xtatadi — haqiqiy metod ham topishi bilan to'xtaydi. ikkinchiOsh ikkinchi parametrni ishlatadi: siz uni uchinchi argument bilan chaqirganingiz uchun u haqiqiy metoddagidek ishladi. Endi findIndex siz uchun "sehr" emas: ichida sikl, callback va to'g'ri imzo.
4-mashq: Vazifalar qadami — refaktoringni boshlaymiz
Endi vazifalar ilovasiga qaytamiz. Bu va keyingi uch darsda biz uning xulqini o'zgartirmaymiz — faqat kodini yaxshilaymiz.
Refaktoring (refactoring) — dastur nima qilishini o'zgartirmasdan, kodini qayta tuzish. Xuddi uyni ta'mirlashdek: devorlar joyida, xonalar o'sha-o'sha, faqat simlar tartibga solinadi. Foydalanuvchi farqni sezmasligi kerak — refaktoringning asosiy qoidasi shu.
1. Ro'yxat tuzing. vazifalar.js da to'rtta for...of sikli bor. Har biri qaysi metodga mos?
| Funksiya | Sikl nima qiladi | Metod | Dars |
|---|---|---|---|
render (filtr tugmalari) |
har tugmaga atribut qo'yadi | forEach |
shu dars |
render (qatorlar) |
har vazifadan li yasaydi |
map |
map |
korinadiganlar |
mos vazifalarni tanlaydi | filter |
filter |
faollarSoni |
bajarilmaganlarni sanaydi | reduce |
reduce |
2. Birinchi siklni almashtiring. Yangi branch oching: git switch -c refactor/hof-metodlar. refactor/ — "xulq o'zgarmaydi, kod yaxshilanadi" degan prefiks. render() dagi filtr tugmalari sikli:
for (const tugma of filtrlar.querySelectorAll("[data-filtr]")) {
const tanlangan = tugma.dataset.filtr === holat.filtr;
tugma.setAttribute("aria-pressed", String(tanlangan));
}Uni forEach ga o'tkazing. Ishora: querySelectorAll qaytaradigan NodeList da forEach bor (Elementlarni tanlash).
Yechim
filtrlar.querySelectorAll("[data-filtr]").forEach((tugma) => {
const tanlangan = tugma.dataset.filtr === holat.filtr;
tugma.setAttribute("aria-pressed", String(tanlangan));
});Callback faqat birinchi parametrni — tugmani — oladi. U DOM'ni o'zgartiradi, bu yon ta'sir — forEach aynan shunday ish uchun. NodeList ning o'zini emas, faqat uning elementlarining atributini o'zgartiryapmiz — «Callback ichida nimani o'zgartirmaslik kerak» bo'limidagi qoida buzilmadi.
Xulq o'zgarmaganini tekshiring. Saytni Live Server'da oching:
- «Faol» ni bosing — u to'q yashil, qolgan ikkitasi oq. DevTools → Elements'da
aria-pressed="true"faqat unda. - «Bajarilgan» → «Hammasi» — tanlov har safar bitta tugmada.
- "Bajarilgan" filtrida yangi vazifa qo'shing — filtr o'zi «Hammasi» ga o'tadi, tugmalar ham.
Commit: Render: filtr tugmalarini forEach bilan yangila. Branch'ni hali main ga qo'shmang — keyingi uch dars ham shu branch'da davom etadi.
Maslahat: Bu almashtirish — eng kichik foyda.
for...ofham,forEachham bu yerda to'g'ri; ko'p jamoalar "har biri uchun yon ta'sir" niyatini aniq aytgani uchunforEachni afzal ko'radi. Haqiqiy foyda keyingi uch siklda: ular 7–8 qatordan 1–3 qatorga tushadi.
Tekshirib ko'ring:
filterdarsidakorinadiganlarnifilterbilan yozamiz. Negaholat.vazifalar.filter(mosmi)deb yozib bo'lmaydi?mosmi(vazifa, filtr)ning imzosiga qarang.
Javob
filter mosmi ni (vazifa, index, array) bilan chaqiradi. Demak mosmi ning ikkinchi parametri filtr ga satr emas, indeks tushadi: 0, 1, 2. 0 === "faol" — false, shuning uchun har vazifa "hammasi" filtridek o'tib ketadi. Xato xabari chiqmaydi — filtr shunchaki ishlamaydi. Kerakli argumentni o'zimiz berishimiz kerak: (vazifa) => mosmi(vazifa, holat.filtr).
10. Real ishda
- React. Ro'yxatni ekranga chiqarishning asosiy usuli —
vazifalar.map(...). Ro'yxatni filtrlash —filter. React kodini o'qiganda bu metodlarni har ekranda ko'rasiz (React — 17-qismda). - Server. Bazadan kelgan buyurtmalar massivi: summani
reducehisoblaydi, faqat to'langanlarinifiltertanlaydi, mijozga ketadigan ko'rinishgamapaylantiradi. - Intervyu. "
forEachvamapning farqi nima?" va "callback qanday argumentlar oladi?" — junior intervyusining eng ko'p uchraydigan savollaridan. Javob:forEach—undefined,map— yangi massiv; callback(element, index, array)oladi. - Kod ko'rib chiqish (code review). Tajribali dasturchi callback ichida massivni o'zgartirgan kodni darhol qaytaradi. Bugungi «Callback ichida nimani o'zgartirmaslik kerak» bo'limi — ish joyidagi real talab.
Xulosa
- Massivning HOF metodlari ichida sikl yashiringan — siz faqat callback berasiz.
- Callback imzosi:
(element, index, array). Nomlar ixtiyoriy, tartib qat'iy. - Metodlar callback qaytargan qiymat bilan har xil ish qiladi:
findtopadi,somejavob beradi,forEachtashlab yuboradi. - Ikkinchi argument (
thisArg) callback'ga bormaydi; tayyor funksiyaning ikkinchi parametriga esa indeks tushadi. - Callback faqat "so'rasin": aylanayotgan massivni va uning obyektlarini o'zgartirmasin.
forEach— yon ta'sir uchun. - Deklarativ yozuv niyatni nomda aytadi va xato uchun kam joy qoldiradi.
Keyingi dars: map: har elementni o'zgartirish — har elementni aylantirib, xuddi shu uzunlikdagi yangi massiv yasaymiz va vazifalar ning ro'yxat chizish siklini bitta qatorga tushiramiz.
Manbalar
- MDN: "Array" — "Iterative methods" bo'limi; "Array.prototype.forEach()" — developer.mozilla.org
- ECMAScript 2025 Language Specification: "Array.prototype.forEach" — tc39.es/ecma262
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!