IlmHamroh
JavaScript Full-stack/10-qism. JavaScript chuqur1/65-dars21 daqiqa
Mundarija (31)

JavaScript massiv metodlari: callback imzosi va HOF metodlar oilasi

Qisqacha: forEach, map, filter, find, some kabi 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.
  • vazifalar ilovasining kodini uning ishini o'zgartirmay yaxshilashni boshlaysiz: birinchi siklni forEach ga 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:

js
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:

js
["osh", "manti"].forEach(console.log);

Konsolda:

text
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:

js
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:

text
1/2: osh
2/2: manti

Endi 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.

js
const navbat = ["Ali", "Malika", "Jasur"];

navbat.forEach((_, i) => {
  console.log(`${i + 1}-o'rin band`);
});

Konsolda:

text
1-o'rin band
2-o'rin band
3-o'rin band

Bu 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?

js
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:

text
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:

js
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)); // undefined

Callback 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. find va findIndex — 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:

js
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:

js
function chiqar(narx, birlik) {
  console.log(narx, birlik);
}

[35000, 28000].forEach(chiqar, "so'm");

Konsolda:

text
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.

js
function chiqar(narx, birlik) {
  console.log(narx, birlik);
}

[35000, 28000].forEach((narx) => chiqar(narx, "so'm"));

Konsolda:

text
35000 so'm
28000 so'm

Qoida: 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:

js
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:

js
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:

js
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); // 31500

Konsolda:

text
Osh: 31500
Manti: 27000
31500

Aksiya 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:

js
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); // 35000

Konsolda:

text
Osh: 31500
Manti: 27000
35000

Menyu 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: vazifalar dagi vazifaniAlmashtir funksiyasi holat ni 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; — asl menyu o'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:

js
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); // 2

Ikkinchi 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. filter so'zini ko'rgan odam darhol tushunadi: tanlash bo'lyapti. Sikl ichini o'qib, buni topish shart emas.
  • Xato uchun joy kam. push ni unutish, <= bilan chegaradan chiqish, noto'g'ri indeks — bularning hammasi metod ichida, u esa sinalgan.
  • O'zgaruvchan "qutilar" yo'q. let soni yoki bo'sh natija massivi 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

js
function chiqar(taom) {
  console.log(taom);
}

["osh", "manti"].forEach(chiqar());

Avval undefined chiqadi, keyin xato:

text
TypeError: undefined is not a function

Tarjimasi: "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

js
const narxlar = [28000, 35000];

const topildi = narxlar.find((narx) => {
  narx > 30000;
});

console.log(topildi); // undefined

Jingalak 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.

js
const menyu = ["Osh", "Lag'mon", "Manti", "Ko'k choy"];

Natija to'rt qator bo'lsin: birinchisi 1. Osh, oxirgisi 4. Ko'k choy.

Yechim
js
const menyu = ["Osh", "Lag'mon", "Manti", "Ko'k choy"];

menyu.forEach((taom, i) => {
  console.log(`${i + 1}. ${taom}`);
});

Konsolda:

text
1. Osh
2. Lag'mon
3. Manti
4. Ko'k choy

Indeks 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].

js
const navbat = ["Ali", "Malika", "Bobur"];
Yechim
js
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:

text
Ali — navbat boshida
Malika — Ali dan keyin
Bobur — Malika dan keyin

return 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:

  • shart callback'ini har element uchun (element, index, array) bilan chaqirsin;
  • birinchi true bergan elementning indeksini qaytarsin va to'xtasin;
  • hech biri mos kelmasa — -1.

So'ng uni haqiqiy findIndex bilan uchta shartda solishtiring.

Yechim
js
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)); // -1

return 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:

js
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
js
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...of ham, forEach ham bu yerda to'g'ri; ko'p jamoalar "har biri uchun yon ta'sir" niyatini aniq aytgani uchun forEach ni afzal ko'radi. Haqiqiy foyda keyingi uch siklda: ular 7–8 qatordan 1–3 qatorga tushadi.

Tekshirib ko'ring: filter darsida korinadiganlar ni filter bilan yozamiz. Nega holat.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 reduce hisoblaydi, faqat to'langanlarini filter tanlaydi, mijozga ketadigan ko'rinishga map aylantiradi.
  • Intervyu. "forEach va map ning 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: find topadi, some javob beradi, forEach tashlab 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
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript massiv metodlari: callback imzosi va HOF metodlar oilasi — IlmHamroh