IlmHamroh
JavaScript Full-stack/10-qism. JavaScript chuqur3/65-dars22 daqiqa
Mundarija (38)

JavaScript filter metodi: massivdan shart bo'yicha tanlash

Qisqacha: filter massivning har elementi uchun callback'ni chaqiradi va callback truthy qiymat qaytargan elementlardan yangi massiv yasaydi: narxlar.filter((n) => n <= 30000). Asl massiv o'zgarmaydi, natija esa bo'sh bo'lishi ham mumkin — []. "Ro'yxatdan faqat kerakligini qoldir" degan har vazifa — filter ning ishi.

Bu darsda

  • filter bilan sonlar, satrlar va obyektlar massividan kerakli elementlarni tanlay olasiz.
  • Predikat funksiya nima ekanini va unga qanday nom berishni bilasiz.
  • filter(Boolean) ning ishini va uning tuzog'ini tushuntira olasiz.
  • filter va map ni zanjir qilib ulay olasiz va filter, find, some farqini aytib bera olasiz.
  • vazifalar dagi korinadiganlar ni bitta qatorga tushirasiz — 09-qismdagi va'da bajariladi.

Oldin bilishingiz kerak: Callback imzosi va HOF metodlari, map: har elementni o'zgartirish, Boolean va truthy/falsy qiymatlar, Massivda qidirish va tekshirish, Holatdan UI chizish.

1. Nega bu kerak?

09-qismning ikki darsida bir xil kodni yozgan edik. Holatdan UI chizish darsida — korinadiganIshlar, Yakuniy loyiha darsida — korinadiganlar:

js
function korinadiganlar() {
  const natija = [];
  for (const vazifa of holat.vazifalar) {
    if (mosmi(vazifa, holat.filtr)) {
      natija.push(vazifa);
    }
  }
  return natija;
}

Ikkala darsda ham "massivning maxsus filter metodi bor, uni 10-qismda o'rganamiz" degan edik. 09-qism yakunida esa aniqroq va'da berdik: shu funksiyani bitta qatorda yozasiz. Bugun shu va'dani bajaramiz.

Massiv bo'ylab yurish darsida yana bir muammo bor edi. Savatdan hamma "sut" ni splice bilan o'chirmoqchi bo'ldik va bittasi qolib ketdi. O'sha darsda "keyinroq filter bu vazifani massivga tegmasdan, xavfsiz bajaradi" degan edik.

Hayotdan o'xshatish: un elagi. Uyda non yopishdan oldin unni elakdan o'tkazasiz. Mayin un idishga tushadi, kepak va qum elakda qoladi. Elak hech narsani o'zgartirmaydi — faqat tanlaydi. filter ham shunday: elementlar o'zgarmaydi, faqat shartdan o'tganlari yangi massivga tushadi. Inglizcha "filter" so'zining o'zi ham "elak, suzgich" degani.

Reja shunday. Avval filter ni sonlarda ko'ramiz va uning ichini o'zimiz yozib chiqamiz. Keyin callback'ning maxsus nomini — predikatni — o'rganamiz. So'ng truthy/falsy tuzog'i, obyektlar va map bilan zanjir keladi. Oxirida brauzerda jonli qidiruv yasaymiz va vazifalar ga qaytamiz.

Har qadamda bitta savolni yodda tuting: "men tanlayapmanmi yoki aylantiryapmanmi?" Tanlash — filter, aylantirish — map.

2. Birinchi filter

2.1 Arzon narxlar

Talaba mehmon «Bahor»dan 30 000 so'mgacha bo'lgan taomlarni so'radi:

js
const narxlar = [35000, 28000, 30000, 5000];
const arzonlar = narxlar.filter((narx) => narx <= 30000);

console.log(arzonlar); // [ 28000, 30000, 5000 ]
console.log(narxlar); // [ 35000, 28000, 30000, 5000 ]

Callback (narx) => narx <= 30000 har element uchun savolga javob beradi: "seni olaymi?" true qaytsa — element yangi massivga tushadi. false — tushmaydi. Tartib saqlanadi, asl massiv o'zgarmaydi.

Qadamma-qadam ko'ring. Keyingi tugmasini bosib, qaysi element o'tib, qaysi biri qolishini kuzating:

2.2 filter ning va'dalari

Va'da Ma'nosi
Yangi massiv Natija — boshqa massiv, asl massiv o'zgarmaydi
Uzunlik ≤ asl Hech bir element mos kelmasa — bo'sh massiv []
Tartib saqlanadi O'tgan elementlar asl tartibida turadi
Elementlar o'sha-o'sha Elementlar nusxalanmaydi, o'zgarmaydi

map bilan solishtiring. map — uzunlik bir xil, elementlar aylanadi. filter — uzunlik kamayishi mumkin, elementlar o'zgarmaydi. Bittasi "aylantiradi", ikkinchisi "tanlaydi". Ikkalasini bitta metodda qilish kerak bo'lsa — ularni ketma-ket ulaymiz, buni «Zanjir» bo'limida ko'ramiz.

2.3 filter ichidan

filter "sehr" emas. Callback imzosi darsida forEach ning nusxasini yozgan edik. filter ning soddalashtirilgan nusxasi ham bir necha qator — va u 09-qismdagi korinadiganlar ga juda o'xshaydi:

js
function tanla(massiv, predikat) {
  const natija = [];
  for (let i = 0; i < massiv.length; i++) {
    if (predikat(massiv[i], i, massiv)) {
      natija.push(massiv[i]);
    }
  }
  return natija;
}

const narxlar = [35000, 28000, 30000, 5000];
const arzonlar = tanla(narxlar, (n) => n <= 30000);
console.log(arzonlar); // [ 28000, 30000, 5000 ]

Farqi bitta: korinadiganlar da shart (mosmi(...)) ichkariga qotirib yozilgan edi. tanla da esa shart tashqaridan — callback bo'lib keladi. Shuning uchun bitta tanla istalgan massivni istalgan shart bilan elay oladi. filter — xuddi shu tanla, faqat har massivga tayyor holda biriktirilgan.

E'tibor bering: if ichida callback natijasi true bilan solishtirilmayapti — if uning o'zini tekshiradi. Shuning uchun filter truthy va falsy qiymatlar bilan ishlaydi. Bu «Truthy va falsy» bo'limida muhim bo'ladi.

O'zingiz to'ldiring. [3, 8, 1, 9].filter((x) => x > 5) natijasi — [8, ]. [3, 1].filter((x) => x > 5) natijasi — ].

Tekshirib ko'ring: ["osh", "manti", "choy"].filter((t) => t.length > 3) nima qaytaradi?

Javob

[ 'manti', 'choy' ]. "osh" — 3 harf, 3 > 3 — false, u o'tmadi. "manti" (5) va "choy" (4) o'tdi. Elementlar o'zgarmadi — faqat ulardan biri tushib qoldi.

3. Predikat — "ha yoki yo'q" funksiya

3.1 Atama

filter ga beriladigan callback'ning maxsus nomi bor. Predikat (predicate) — true yoki false qaytaradigan, ya'ni "ha/yo'q" savoliga javob beradigan funksiya. O'xshatish: to'y zali eshigidagi tekshiruvchi. U har mehmonga bitta savol beradi: "taklifnomangiz bormi?" Javob ha bo'lsa — kiradi, yo'q bo'lsa — yo'q. Tekshiruvchi mehmonni o'zgartirmaydi, faqat qaror qabul qiladi.

Siz predikatlarni allaqachon yozgansiz. find, some va every ham predikat oladi (Massivda qidirish). 09-qismdagi mosmi(vazifa, filtr) ham predikat — "bu vazifa filtrga mosmi?".

3.2 Predikatga qanday nom berish kerak

Predikat savolga javob beradi, shuning uchun nomi ham savol shaklida bo'lgani yaxshi. O'zbek tilida buning tayyor vositasi bor — "-mi" qo'shimchasi: arzonmi, faolmi, mosmi, bajarilganmi.

js
const menyu = [
  { nom: "Osh", narx: 35000, issiq: true },
  { nom: "Lag'mon", narx: 28000, issiq: true },
  { nom: "Manti", narx: 30000, issiq: true },
  { nom: "Ko'k choy", narx: 5000, issiq: false },
];

const arzonmi = (taom) => taom.narx <= 30000;
const issiqmi = (taom) => taom.issiq;

const arzonlar = menyu.filter(arzonmi);
const issiqlar = menyu.filter(issiqmi);

const nomlar = arzonlar.map((t) => t.nom);

console.log(nomlar); // [ "Lag'mon", 'Manti', "Ko'k choy" ]
console.log(issiqlar.length); // 3

menyu.filter(arzonmi) — "menyudan arzonlarini tanla" deb o'qiladi. Natijani o'qish uchun map bilan nomlarni oldik — bu ham o'tgan darsdagi usul.

Predikatlarni qavssiz, to'g'ridan-to'g'ri berdik. Bu xavfsiz, chunki ular bitta parametr oladi. Ikki parametrli mosmi(vazifa, filtr) ni esa bunday berib bo'lmaydi — buni «Vazifalar qadami» da ko'ramiz.

3.3 Bir nechta shart

Shartlarni mantiqiy operatorlar bilan birlashtiring:

js
const menyu = [
  { nom: "Osh", narx: 35000, issiq: true },
  { nom: "Lag'mon", narx: 28000, issiq: true },
  { nom: "Ko'k choy", narx: 5000, issiq: false },
];

const arzonIssiq = menyu.filter((t) => t.issiq && t.narx <= 30000);
console.log(arzonIssiq.map((t) => t.nom)); // [ "Lag'mon" ]

&& — ikkala shart ham bajarilsin. || — kamida bittasi. Shart uzun bo'lib ketsa, alohida nomli predikat qiling — o'qilishi osonlashadi.

3.4 Teskari shart

Nomli predikatning yana bir foydasi — uni teskarisiga aylantirish oson. Arzonlar bor, endi qimmatlar kerak. Yangi predikat yozish shart emas:

js
const menyu = [
  { nom: "Osh", narx: 35000 },
  { nom: "Ko'k choy", narx: 5000 },
];
const arzonmi = (taom) => taom.narx <= 30000;

const qimmatlar = menyu.filter((taom) => !arzonmi(taom));
console.log(qimmatlar.map((t) => t.nom)); // [ 'Osh' ]

! — mantiqiy "emas". Arrow funksiya predikatni chaqiradi va javobini teskarisiga o'giradi. Shart bitta joyda — arzonmi ichida — yashaydi. Ertaga "arzon" chegarasi 25 000 bo'lsa, faqat shu yerni o'zgartirasiz va ikkala ro'yxat ham to'g'ri bo'ladi.

4. Truthy va falsy: filter(Boolean)

4.1 filter faqat true ni kutmaydi

filter callback qaytargan qiymatni true bilan solishtirmaydi. U qiymat truthymi yoki falsymi — shunga qaraydi (Boolean va truthy/falsy). Falsy qiymatlar: false, 0, "", null, undefined, NaN. Qolgan hammasi — truthy.

Shunga asoslangan mashhur yozuv bor:

js
const kiritilgan = ["Ali", "", "Malika", null, "Jasur", undefined];
const ismlar = kiritilgan.filter(Boolean);

console.log(ismlar); // [ 'Ali', 'Malika', 'Jasur' ]

Boolean — tayyor funksiya: u qiymatni mantiqiy qiymatga aylantiradi (Turlarni aniq o'zgartirish). filter uni predikat sifatida chaqiradi. Bo'sh satr, null va undefined falsy — ular tushib qoladi. Formadan kelgan bo'sh maydonlarni tozalashning eng qisqa yo'li shu.

4.2 Tuzoq: 0 ham falsy

js
const narxlar = [5000, 0, 28000];

console.log(narxlar.filter(Boolean)); // [ 5000, 28000 ]

0 ham tushib qoldi! Agar u "bepul ko'k choy" aksiyasi bo'lsa — mijoz uni menyuda ko'rmaydi. filter(Boolean) "bo'sh narsalarni olib tashla" emas, "falsy narsalarni olib tashla" degani. Sonlar bilan aniq shart yozing:

js
const narxlar = [5000, 0, 28000, null];
const borlar = narxlar.filter((n) => n !== null);

console.log(borlar); // [ 5000, 0, 28000 ]

Tekshirib ko'ring: [0, 1, "", "0", false].filter(Boolean) nima qaytaradi?

Javob

[ 1, '0' ]. 0, "" va false — falsy. "0" esa bo'sh bo'lmagan satr — truthy, garchi ichida nol bo'lsa ham (Boolean va truthy/falsy darsidagi tuzoq).

5. Obyektlar bilan filter

5.1 Elementlar nusxalanmaydi

filter yangi massiv yasaydi, lekin ichiga o'sha obyektlarni qo'yadi:

js
const vazifalar = [
  { id: 1, matn: "Non olish", bajarildi: false },
  { id: 2, matn: "DOM darsini takrorlash", bajarildi: true },
];

const faollar = vazifalar.filter((v) => !v.bajarildi);
console.log(faollar[0] === vazifalar[0]); // true

faollar[0].matn = "Non va sut olish";
console.log(vazifalar[0].matn); // Non va sut olish

faollar[0] va vazifalar[0] — bitta obyekt (Havola semantikasi). Filtrlangan massiv orqali o'zgartirsangiz, asl ma'lumot ham o'zgaradi. Bu ko'pincha kerak ham: 09-qismdagi vazifaniAlmashtir aynan shu obyektni o'zgartiradi. Faqat bilib turing: filter — "nusxa" emas, "tanlov".

5.2 Elementni xavfsiz o'chirish

Massiv bo'ylab yurish darsidagi "sut" muammosini eslang: aylanayotganda splice qilsak, element qolib ketadi. filter bilan masala boshqacha qo'yiladi. "Sutlarni o'chir" emas, "sut bo'lmaganlarini qoldir":

js
const savat = ["sut", "sut", "non", "sut"];
const sutsiz = savat.filter((m) => m !== "sut");

console.log(sutsiz); // [ 'non' ]
console.log(savat.length); // 4

Hech narsa qolib ketmadi, chunki filter aylanayotgan massivni o'zgartirmaydi — u yangisini yig'adi. Asl savat butun.

Xuddi shu usul bilan vazifani id bo'yicha o'chirish mumkin. Bu — map darsidagi immutable yangilashning bir turi: asl massivga tegmay, keraksiz elementsiz yangi massiv yasaymiz:

js
const vazifalar = [
  { id: 1, matn: "Non olish" },
  { id: 2, matn: "DOM darsini takrorlash" },
  { id: 3, matn: "Onamga qo'ng'iroq qilish" },
];

const qolganlar = vazifalar.filter((v) => v.id !== 2);
console.log(qolganlar.map((v) => v.id)); // [ 1, 3 ]

Tekshirib ko'ring: Bitta mahsulotni (masalan birinchi "sut" ni) o'chirish kerak bo'lsa, savat.filter((m) => m !== "sut") to'g'ri keladimi?

Javob

Yo'q — u hamma sutni olib tashlaydi. filter "shu shartga mos hamma elementni" deb o'ylaydi. Bitta aniq elementni o'chirish uchun uni noyob belgi bo'yicha tanlang — id yoki indeks: savat.filter((_, i) => i !== 0). Shuning uchun vazifalarda matn emas, id bor.

09-qismdagi vazifaniOchir findIndex va splice bilan aslini o'zgartiradi — bu ham to'g'ri yo'l, holat ni ataylab o'zgartiradigan funksiyada. filter esa yangi massiv kerak bo'lganda — masalan React'da (17-qism) — asosiy usul.

5.3 Indeks bilan: takrorlarni olib tashlash

Callback imzosi darsidagi uchinchi parametr bu yerda chiroyli ishga tushadi. Buyurtmalar ro'yxatidan har taomni bir martadan qoldiramiz:

js
const buyurtmalar = ["osh", "choy", "osh", "manti", "choy"];

const taomlar = buyurtmalar.filter(
  (taom, i, hammasi) => hammasi.indexOf(taom) === i,
);

console.log(taomlar); // [ 'osh', 'choy', 'manti' ]

indexOf qiymatning birinchi uchragan joyini qaytaradi (Massivda qidirish). Har qadamni jadvalda ko'ring:

i taom indexOf(taom) O'tadimi?
0 osh 0 ha — 0 === 0
1 choy 1 ha — 1 === 1
2 osh 0 yo'q — 0 === 2 emas
3 manti 3 ha
4 choy 1 yo'q — 1 === 4 emas

Ikkinchi "osh" 2-indeksda, lekin indexOf("osh") uni emas, 0-indeksdagi birinchisini topadi. Indekslar mos kelmaydi — u tushib qoladi. Har qiymatning faqat birinchi nusxasi o'tadi. Bu ishni yanada qisqa qiladigan Set ham bor — Set darsida.

6. Zanjir: filter + map

6.1 Ketma-ket ulash

filter massiv qaytaradi. Massivda esa map bor. Demak ularni nuqta bilan ketma-ket yozish mumkin. Oshxona ekraniga faqat faol vazifalarning matnlari kerak:

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 },
];

const matnlar = vazifalar
  .filter((v) => !v.bajarildi)
  .map((v) => v.matn);

console.log(matnlar); // [ 'Non olish', "Onamga qo'ng'iroq qilish" ]

Har metod oldingisining natijasini oladi. Sxemadagi strelkalarga qarang — har bosqichda massiv qanday o'zgaradi:

flowchart LR
  A["vazifalar: 3 ta obyekt"] -- "filter: faolmi?" --> B["2 ta obyekt"]
  B -- "map: matnini ol" --> C["2 ta satr"]

Zanjirni har metod alohida qatorda, nuqta bilan boshlab yozish odat — o'qish oson va telefonda ham sig'adi.

6.2 Tartib muhim

Nega avval filter, keyin map? Ikki sabab bor. Birinchisi: map dan keyin bajarildi maydoni yo'qoladi — satrlarda uni tekshirib bo'lmaydi. Ikkinchisi: avval tanlasak, map kamroq elementni aylantiradi. Ming vazifadan o'ntasi faol bo'lsa, map ming marta emas, o'n marta ishlaydi. Qoida sifatida eslab qoling: avval keraksizini olib tashlang, keyin qolganini ishlang.

Zanjirlar haqida batafsil — o'qiluvchanlik, tezlik va qachon oddiy sikl yaxshiroq — Metod zanjiri darsida.

6.3 Obyektni filtrlash

Obyekt bo'ylab yurish darsida arzon taomlarni sikl bilan tanlagan edik va "filter bilan bu bitta qatorga tushadi" degan edik:

js
const menyu = { osh: 35000, lagmon: 28000, choy: 5000, non: 4000 };

const arzonMenyu = Object.fromEntries(
  Object.entries(menyu).filter(([, narx]) => narx <= 10000),
);

console.log(arzonMenyu); // { choy: 5000, non: 4000 }

([, narx]) — juftlikning birinchi qismini (nomni) o'tkazib, faqat narxni olamiz (Massiv destructuring). Non narxi — misol uchun.

Tekshirib ko'ring: [5, 12, 8, 20].filter((x) => x > 6).map((x) => x * 10) nima qaytaradi?

Javob

[ 120, 80, 200 ]. Avval filter: [12, 8, 20] (5 o'tmadi). Keyin map har birini 10 ga ko'paytirdi. Uchta element kirdi — uchta chiqdi.

7. filter, find va some farqi

Uchalasi ham predikat oladi. Farq — nima qaytarishida va qachon to'xtashida:

Metod Qaytaradi Hech biri mos kelmasa To'xtaydimi?
filter mos hammasi — massiv [] yo'q, oxirigacha
find birinchi mos element undefined ha, topishi bilan
some true / false false ha, topishi bilan

Qaysi birini tanlash — savolga bog'liq. "Arzon taomlar qaysilar?" — filter. "Birinchi arzon taom qaysi?" — find. "Arzon taom bormi?" — some. Massivda qidirish darsida "find va filter farqi" intervyu savoli ekanini aytgan edik — mana javob.

filter ni find yoki some o'rnida ishlatish — ko'p uchraydigan xato. Buni «Ko'p uchraydigan xatolar» bo'limida ko'ramiz.

Farqni bitta tajribada ko'ring. Callback ichiga kuzatish uchun console.log qo'yamiz va uchala metodga bir xil savol beramiz — "30 000 dan arzonmi?":

js
const narxlar = [35000, 28000, 5000];
let chaqiruv = 0;
const arzonmi = (n) => {
  chaqiruv++;
  return n < 30000;
};

console.log(narxlar.filter(arzonmi), chaqiruv); // [ 28000, 5000 ] 3
chaqiruv = 0;
console.log(narxlar.find(arzonmi), chaqiruv); // 28000 2
chaqiruv = 0;
console.log(narxlar.some(arzonmi), chaqiruv); // true 2

filter callback'ni uch marta chaqirdi — u har elementni ko'rishi shart, chunki "hammasi" kerak. find va some ikkinchi elementda javob topib, to'xtadi. Ming elementli ro'yxatda birinchisi mos kelsa, farq 1 ga qarshi 1000 bo'ladi.

Tekshirib ko'ring: Telegram bot foydalanuvchi yozgan buyruq ro'yxatda borligini tekshirishi kerak. filter, find yoki some — qaysi biri?

Javob

some — savol "bormi?", javob true/false. U topishi bilan to'xtaydi. filter ham ishlaydi (.length > 0), lekin har buyruqni behuda tekshiradi va keraksiz massiv yasaydi.

8. Brauzerda: jonli qidiruv

Mehmon menyudan taom qidiradi. Har harf yozilganda ro'yxat yangilanadi. Bu filter ning eng ko'p uchraydigan brauzer ishi: holat (menyu) o'zgarmaydi, ekranga esa uning filtrlangan qismi chiziladi (Holatdan UI chizish). Hodisa — input (input va change):

html
<style>
  body { margin: 1rem; font: 1rem/1.5 system-ui, sans-serif; }
  input {
    font: inherit;
    min-height: 2.75rem;
    padding: 0.5rem;
    border: 2px solid #5b6660;
    border-radius: 0.5rem;
  }
  ul { padding-left: 1.25rem; }
</style>
<label for="qidiruv">Taom qidirish</label>
<input id="qidiruv" type="search" autocomplete="off">
<p id="soni" aria-live="polite"></p>
<ul id="menyu"></ul>
<script>
  const menyu = [
    { nom: "Osh", narx: 35000 },
    { nom: "Lag'mon", narx: 28000 },
    { nom: "Manti", narx: 30000 },
    { nom: "Ko'k choy", narx: 5000 },
  ];
  const maydon = document.getElementById("qidiruv");
  const royxat = document.getElementById("menyu");
  const soni = document.getElementById("soni");

  function mosmi(taom, soz) {
    return taom.nom.toLowerCase().includes(soz.toLowerCase());
  }

  function taomQatori(taom) {
    const li = document.createElement("li");
    li.textContent = `${taom.nom} — ${taom.narx} so'm`;
    return li;
  }

  function render(soz) {
    const topilganlar = menyu.filter((taom) => mosmi(taom, soz));
    royxat.replaceChildren(...topilganlar.map(taomQatori));
    soni.textContent = `${topilganlar.length} ta taom topildi`;
  }

  maydon.addEventListener("input", () => {
    render(maydon.value.trim());
  });

  render("");
  console.log(soni.textContent);
</script>

Konsolda:

text
4 ta taom topildi

Sinab ko'ring:

  • Maydonga o yozing — uchta taom qoladi: Osh, Lag'mon, Ko'k choy. Ularning hammasida "o" harfi bor.
  • ma deb yozing — faqat Manti. MA deb yozsangiz ham — natija o'sha: ikkala tomon toLowerCase bilan kichik harfga keltirilgan (Matnni o'zgartirish).
  • palov deb yozing — ro'yxat bo'sh, "0 ta taom topildi". filter xato bermadi, shunchaki [] qaytardi.
  • Maydonni tozalang — to'rttala taom qaytadi. Menyu hech qachon o'zgarmagan edi.

Bu kodda muhim bir qaror bor: filter natijasi hech qayerda saqlanmaydi. topilganlar — render ichidagi vaqtinchalik o'zgaruvchi, har harfda qaytadan hisoblanadi. menyu esa doim to'liq turadi. Agar natijani menyu ning o'ziga yozsak (menyu = menyu.filter(...)), "palov" deb yozgan mehmon menyuni butunlay yo'qotardi — maydonni tozalasa ham taomlar qaytmasdi. Filtrlangan ro'yxat — hosila ma'lumot: u har safar holatdan qayta hisoblanadi va alohida saqlanmaydi (Holatdan UI chizish darsidagi qoida).

Son aria-live="polite" hududida — ko'zi ojiz mehmon Malika NVDA bilan har harfdan keyin "2 ta taom topildi" deb eshitadi (Dinamik UI'da qulaylik). Bu yerda ham ikki parametrli mosmi arrow funksiyaga o'ralgan — sababini quyida, «Vazifalar qadami» da ko'rasiz.

9. Ko'p uchraydigan xatolar

9.1 Jingalak qavsli predikatda return yo'q

js
const narxlar = [35000, 28000, 5000];

const arzonlar = narxlar.filter((narx) => {
  narx <= 30000;
});

console.log(arzonlar); // []

Bo'sh massiv — xatosiz. Callback har safar undefined qaytardi, u esa falsy. Bitta ham element o'tmadi. Tuzatish: (narx) => narx <= 30000 yoki { return narx <= 30000; }. Bo'sh natijani ko'rsangiz, avval shu return ni tekshiring.

9.2 Bo'sh massiv — truthy

js
const menyu = [{ nom: "Osh", narx: 35000 }];
const topilgan = menyu.filter((t) => t.nom === "Palov");

if (topilgan) {
  console.log("Bor!");
}
console.log(topilgan); // []

Konsolda:

text
Bor!
[]

Palov topilmadi, lekin "Bor!" chiqdi. Sabab: filter doim massiv qaytaradi, bo'sh massiv [] esa truthy (Boolean va truthy/falsy). Tuzatish: savol "bormi?" bo'lsa — some ishlating: menyu.some((t) => t.nom === "Palov"). Yoki uzunlikni tekshiring: topilgan.length > 0.

9.3 Bitta element uchun filter(...)[0]

js
const menyu = [
  { nom: "Osh", narx: 35000 },
  { nom: "Manti", narx: 30000 },
];

const osh = menyu.filter((t) => t.nom === "Osh")[0];
console.log(osh.narx); // 35000

Ishlaydi, lekin ortiqcha ish qiladi: filter birinchisini topgandan keyin ham oxirigacha yuradi va keraksiz massiv yasaydi. Tuzatish: menyu.find((t) => t.nom === "Osh") — topishi bilan to'xtaydi va obyektning o'zini qaytaradi.

9.4 Predikat ichida ma'lumotni o'zgartirish

js
const vazifalar = [{ id: 1, bajarildi: false }];

const faollar = vazifalar.filter((v) => {
  v.korildi = true;
  return !v.bajarildi;
});

console.log(vazifalar[0].korildi); // true

Predikat "faqat so'rash" o'rniga asl obyektga yangi maydon yozib qo'ydi. filter chaqirilgani asl ma'lumotni o'zgartirdi — kodni o'qigan odam buni hech kutmaydi. Callback imzosi darsidagi qoida: callback toza bo'lsin. Tuzatish: predikat faqat return qilsin; belgilash kerak bo'lsa — alohida qadamda va ataylab.

9.5 Natijani saqlamaslik

savat.filter((m) => m !== "sut"); deb yozib, savat dan sut o'chishini kutish. filter aslini o'zgartirmaydi — natijani yangi o'zgaruvchiga yozing: const sutsiz = savat.filter(...). Yoki, let bilan e'lon qilingan bo'lsa, qayta tayinlang: savat = savat.filter(...).

10. Mashqlar

1-mashq (oson): O'tgan talabalar

Imtihon ballari berilgan. filter bilan 60 va undan yuqori ballarni tanlang va nechta talaba o'tganini chiqaring.

js
const ballar = [45, 78, 60, 91, 33, 59];
Yechim
js
const ballar = [45, 78, 60, 91, 33, 59];
const otganlar = ballar.filter((ball) => ball >= 60);

console.log(otganlar); // [ 78, 60, 91 ]
console.log(otganlar.length); // 3

>= — 60 ham o'tadi. > yozilsa, 60 ballik talaba nohaq yiqilardi.

2-mashq (o'rta): Yetkazilmagan buyurtmalar

Kuryer Jasurga hali yetkazilmagan buyurtmalarning manzillari kerak. filter va map zanjiri bilan manzillar massivini yasang.

js
const buyurtmalar = [
  { id: 1, manzil: "Chilonzor 9", yetkazildi: true },
  { id: 2, manzil: "Yunusobod 4", yetkazildi: false },
  { id: 3, manzil: "Sergeli 2", yetkazildi: false },
];
Yechim
js
const buyurtmalar = [
  { id: 1, manzil: "Chilonzor 9", yetkazildi: true },
  { id: 2, manzil: "Yunusobod 4", yetkazildi: false },
  { id: 3, manzil: "Sergeli 2", yetkazildi: false },
];

const manzillar = buyurtmalar
  .filter((b) => !b.yetkazildi)
  .map((b) => b.manzil);

console.log(manzillar); // [ 'Yunusobod 4', 'Sergeli 2' ]

Avval tanladik, keyin aylantirdik. Teskari tartibda yozsangiz, map dan keyin yetkazildi maydoni yo'qoladi va filtrlab bo'lmaydi.

3-mashq (qiyin): Qidiruv funksiyasi

qidir(menyu, soz, eng = Infinity) funksiyasini yozing. U nomida soz bor (katta-kichik harf farqsiz) va narxi eng dan oshmaydigan taomlarning nomlarini qaytarsin. eng berilmasa — narx cheklanmaydi (Default qiymatlar).

Yechim
js
const menyu = [
  { nom: "Osh", narx: 35000 },
  { nom: "Lag'mon", narx: 28000 },
  { nom: "Manti", narx: 30000 },
  { nom: "Ko'k choy", narx: 5000 },
];

function qidir(taomlar, soz, eng = Infinity) {
  const kichik = soz.toLowerCase();
  return taomlar
    .filter((t) => t.nom.toLowerCase().includes(kichik))
    .filter((t) => t.narx <= eng)
    .map((t) => t.nom);
}

console.log(qidir(menyu, "O")); // [ 'Osh', "Lag'mon", "Ko'k choy" ]
console.log(qidir(menyu, "o", 30000)); // [ "Lag'mon", "Ko'k choy" ]
console.log(qidir(menyu, "palov")); // []

soz.toLowerCase() bir marta, sikldan tashqarida hisoblandi — har element uchun qayta hisoblash shart emas. Ikki filter ni bitta && bilan ham yozsa bo'ladi — ikkalasi ham to'g'ri. Alohida yozilgani o'qishda ikki aniq qadamga bo'linadi. Infinity — har qanday sondan katta, shuning uchun narx <= Infinity doim true (Number turi).

4-mashq: Vazifalar qadami — korinadiganlar bitta qatorda

refactor/hof-metodlar branch'ida davom etamiz. 09-qismdagi va'da: korinadiganlar ni filter bilan yozing. Xulq o'zgarmasin.

Ishora: Callback imzosi darsi oxiridagi savolni eslang — nega holat.vazifalar.filter(mosmi) yozib bo'lmaydi?

Yechim
js
function korinadiganlar() {
  return holat.vazifalar.filter(
    (vazifa) => mosmi(vazifa, holat.filtr),
  );
}

8 qator — bitta return ga tushdi (uzun bo'lgani uchun uch qatorga bo'lib yozdik). mosmi ga o'zgarish kerak emas: u allaqachon predikat edi.

.filter(mosmi) nega yaramaydi — Node'da o'zingiz ko'ring. Eski sikl, yangi filter va xato varianti bir xil holat da:

js
const holat = {
  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 },
  ],
  filtr: "faol",
};

function mosmi(vazifa, filtr) {
  if (filtr === "faol") {
    return !vazifa.bajarildi;
  }
  if (filtr === "bajarilgan") {
    return vazifa.bajarildi;
  }
  return true;
}

function eskisi() {
  const natija = [];
  for (const vazifa of holat.vazifalar) {
    if (mosmi(vazifa, holat.filtr)) {
      natija.push(vazifa);
    }
  }
  return natija;
}

const yangisi = () =>
  holat.vazifalar.filter((vazifa) => mosmi(vazifa, holat.filtr));
const xatosi = () => holat.vazifalar.filter(mosmi);

const idlar = (royxat) => royxat.map((v) => v.id).join(",");
for (const filtr of ["hammasi", "faol", "bajarilgan"]) {
  holat.filtr = filtr;
  const ustunlar = [eskisi(), yangisi(), xatosi()].map(idlar);
  console.log(filtr, ...ustunlar);
}

Konsolda:

text
hammasi 1,2,3 1,2,3 1,2,3
faol 1,3 1,3 1,2,3
bajarilgan 2 2 1,2,3

Eski va yangi ustunlar hamma filtrda bir xil — refaktoring xulqni o'zgartirmadi. Uchinchi ustun esa doim 1,2,3: mosmi ning filtr parametriga indeks (0, 1, 2) tushdi va har vazifa "hammasi" dagidek o'tdi. Xato xabari yo'q — shuning uchun bunday tekshiruv foydali.

Brauzerda tekshiring:

  • «Faol» — "Non olish" va "Onamga qo'ng'iroq qilish". «Bajarilgan» — faqat "DOM darsini takrorlash". «Hammasi» — uchalasi.
  • «Faol» da vazifani belgilang — u ro'yxatdan chiqadi, fokus qo'shnisiga o'tadi, hisob kamayadi.
  • «Faol» da ikkalasini belgilang — "Faol vazifa yo'q.". filter bo'sh massiv qaytardi, render() uni avvalgidek ko'rsatdi.

09-qismdagi Yakuniy loyiha 2-mashqi (bajarilganlarniTozala) ni bajargan bo'lsangiz, undagi for...of ni ham almashtiring: holat.vazifalar = holat.vazifalar.filter((v) => !v.bajarildi);. O'chirilganlar soni — eski va yangi uzunliklar farqi.

Commit: Filtr: korinadiganlar ni filter bilan yoz.

11. Real ishda

  • Qidiruv va filtrlar. Internet do'kondagi "narx: 100 000 gacha", "faqat chegirmadagilar" tugmalari — ichida filter. Telegram kontaktlari ichida qidirish ham shunday ishlaydi.
  • Ma'lumotni tozalash. Formadan yoki fayldan kelgan ro'yxatdan bo'sh qatorlarni olib tashlash: qatorlar.filter((q) => q.trim() !== "").
  • Ruxsatlar. Admin panelda foydalanuvchiga faqat ruxsati bor menyu bandlari ko'rsatiladi: bandlar.filter((b) => ruxsatlar.includes(b.ruxsat)). Lekin xavfsizlik serverda ham tekshiriladi — brauzerdagi filter ni foydalanuvchi DevTools'da chetlab o'tishi mumkin.
  • Hisobotlar. "Bu oy to'langan buyurtmalar", "Toshkentdagi mijozlar" — har hisobot boshida filter turadi, keyin map va yig'indi. Yig'indini qanday olish — keyingi darsda.
  • Intervyu. "filter va find farqi?", "filter asl massivni o'zgartiradimi?", "[0, 1, ''].filter(Boolean) nima beradi?" — endi uchalasiga ham javobingiz bor.

Xulosa

  • filter predikat truthy qaytargan elementlardan yangi massiv yasaydi; asl massiv o'zgarmaydi.
  • Natija qisqaroq yoki bo'sh ([]) bo'lishi mumkin; elementlar nusxalanmaydi — o'sha obyektlar.
  • Predikat nomi savol shaklida: arzonmi, faolmi. Ikki parametrlisini arrow bilan o'rang.
  • filter(Boolean) falsy qiymatlarni, shu jumladan 0 ni ham olib tashlaydi.
  • Avval filter, keyin map — tanlash, keyin aylantirish.
  • Hammasi kerak — filter, birinchisi — find, bormi-yo'qmi — some.
  • Filtrlangan ro'yxat — hosila: uni har safar holatdan qayta hisoblang, asl massiv o'rniga saqlamang. Elementni xavfsiz o'chirish — filter((v) => v.id !== id), aylanayotganda splice emas.

Keyingi dars: reduce: massivni bitta qiymatga yig'ish — massivdan son, obyekt yoki istalgan natijani akkumulyator bilan yig'amiz va vazifalar dagi oxirgi for...of siklini ham almashtiramiz.

Manbalar

  • MDN: "Array.prototype.filter()" — developer.mozilla.org
  • MDN: "Truthy", "Falsy" — developer.mozilla.org
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript filter metodi: massivdan shart bo'yicha tanlash — IlmHamroh