Mundarija (31)
- Bu darsda
- 1. Nega bu kerak?
- 2. Birinchi map
- 2.1 Sonlarni aylantirish
- 2.2 map ning uchta va'dasi
- 2.3 Satrlarni aylantirish va indeks
- 2.4 map o'rtada to'xtamaydi
- 2.5 Nomli callback yoki joyida arrow?
- 3. Obyektlar massivi bilan map
- 3.1 Bitta maydonni ajratib olish
- 3.2 Yangi obyekt yasash
- 3.3 Ehtiyot bo'ling: map ham obyektni buzishi mumkin
- 3.4 Bitta elementni yangilash (immutable)
- 3.5 Ichma-ich ma'lumot: map ichida map
- 4. Obyektni map bilan qayta ishlash
- 5. map va forEach: qaysi biri qachon
- 6. Brauzerda: map bilan elementlar yasash
- 7. Mashhur tuzoq: ["1", "2", "3"].map(parseInt)
- 8. Ko'p uchraydigan xatolar
- 8.1 Jingalak qavsli callback'da return yo'q
- 8.2 Obyektni qavssiz qaytarish
- 8.3 Natijani saqlamaslik
- 8.4 NodeList da map yo'q
- 9. Mashqlar
- 1-mashq (oson): Chek qatorlari
- 2-mashq (o'rta): Buyurtma summasi
- 3-mashq (qiyin): Savatda sonni o'zgartirish
- 4-mashq: Vazifalar qadami — qatorlarni map bilan yasang
- 10. Real ishda
- Xulosa
- Manbalar
JavaScript map metodi: massivning har elementini o'zgartirish
Qisqacha:
mapmassivning har elementi uchun callback'ni chaqiradi va callback qaytargan qiymatlardan yangi massiv yasaydi:narxlar.map((n) => n * 2). Yangi massiv doim asl massiv bilan bir xil uzunlikda bo'ladi, asl massiv esa o'zgarmaydi. "Har birini boshqa ko'rinishga aylantir" degan har vazifa —mapning ishi.
Bu darsda
mapbilan sonlar, satrlar va obyektlar massivini aylantira olasiz.mapvaforEachfarqini aniq aytib bera olasiz.- Massivdagi bitta obyektni asl ma'lumotga tegmasdan yangilay olasiz.
["1", "2", "3"].map(parseInt)nega[1, NaN, NaN]berishini tushuntira olasiz.vazifalardagi ro'yxat chizish siklinimapbilan qayta yozasiz.
Oldin bilishingiz kerak: Callback imzosi va HOF metodlari, Function expression va arrow funksiyalar, Obyekt bo'ylab yurish, Spread va rest operatori, Sayoz va chuqur nusxalash.
1. Nega bu kerak?
Massiv bo'ylab yurish darsida savatdagi mahsulotlarni katta harfga o'tkazgan edik. forEach natija qaytarmagani uchun shunday yozdik:
const savat = ["non", "sut"];
const kattaHarfli = [];
for (const m of savat) {
kattaHarfli.push(m.toUpperCase());
}
console.log(kattaHarfli); // [ 'NON', 'SUT' ]O'sha darsda "keyinchalik buni map bitta qatorda qiladi" degan edik. 09-qismdagi vazifalar ning render() funksiyasida ham shu qolip bor: har vazifadan bitta li yasab, qutiga qo'shamiz.
Bu qolipning tuzilishi doim bir xil:
- Bo'sh massiv yaratiladi.
- Har element olinadi va boshqa ko'rinishga aylantiriladi.
- Natija yangi massivga
pushqilinadi.
O'zgaradigan qismi faqat ikkinchi qadam — "nimaga aylantiramiz". Qolgani har safar takrorlanadi. Hayotdan o'xshatish: tandir. Nonvoy tandirga 10 ta xamir yopadi — 10 ta non uzib oladi. Har xamir nonga aylanadi, soni esa o'zgarmaydi. map — shunday tandir: siz faqat "xamirdan non qanday chiqadi" degan qoidani berasiz. Bitta farqi bor: tandirda xamir tugaydi, map da esa asl massiv joyida qoladi — nonlar yangi savatga tushadi.
Bu darsda map ni avval sonlarda, keyin obyektlar va DOM elementlarida ishlatamiz. Oxirida vazifalar ning render() funksiyasidagi siklni ham map ga o'tkazamiz. Callback imzosi darsidagi bilim bu yerda ham kerak bo'ladi: map callback'ni o'sha uchta argument bilan chaqiradi va bu bitta mashhur tuzoqqa olib keladi.
2. Birinchi map
2.1 Sonlarni aylantirish
«Bahor»da mijozlar ko'pincha ikki porsiya olishadi. Har taomning ikki porsiyalik narxini hisoblaymiz:
const narxlar = [35000, 28000, 30000];
const ikkiPorsiya = narxlar.map((narx) => narx * 2);
console.log(ikkiPorsiya); // [ 70000, 56000, 60000 ]
console.log(narxlar); // [ 35000, 28000, 30000 ]Callback (narx) => narx * 2 har elementni oladi va yangi qiymat qaytaradi. map shu qaytgan qiymatlarni tartib bilan yangi massivga yig'adi. Ikkinchi qatorga qarang: asl narxlar o'zgarmadi.
Bu ish transformatsiya (transformation) deyiladi — har elementni boshqa ko'rinishga aylantirish. Matematikadagi "har x ga 2x mos keladi" g'oyasining o'zi.
Endi qadamma-qadam ko'ring. Keyingi tugmasini bosib, yangi massiv qanday to'lib borishini kuzating:
2.2 map ning uchta va'dasi
map har doim uchta narsani kafolatlaydi:
| Va'da | Ma'nosi |
|---|---|
| Yangi massiv | Natija — boshqa massiv, ikkiPorsiya === narxlar — false |
| Uzunlik bir xil | 3 ta element kirdi — 3 ta chiqadi, bittasi ham tushib qolmaydi |
| Tartib saqlanadi | 0-elementning natijasi 0-o'rinda, 1-niki 1-o'rinda |
Ikkinchi va'da muhim. map element tanlamaydi. Callback biror elementda hech narsa qaytarmasa ham, o'sha o'ringa undefined tushadi — element yo'qolmaydi. Elementlarning bir qismini tanlash kerak bo'lsa, bu boshqa metodning ishi — keyingi darsdagi filter.
2.3 Satrlarni aylantirish va indeks
Callback istalgan turdagi qiymat qaytara oladi. Son kirib, satr chiqishi mumkin:
const narxlar = [35000, 28000, 30000];
const yozuvlar = narxlar.map((narx) => `${narx} so'm`);
console.log(yozuvlar); // [ "35000 so'm", "28000 so'm", "30000 so'm" ]Callback imzosi darsidagi qoida map da ham amal qiladi: ikkinchi parametr — indeks. Menyuni raqamlaymiz va join bilan bitta matnga ulaymiz (Kesish, birlashtirish va matnga aylantirish):
const taomlar = ["Osh", "Lag'mon", "Manti"];
const qatorlar = taomlar.map((taom, i) => `${i + 1}. ${taom}`);
console.log(qatorlar.join("\n"));Konsolda:
1. Osh
2. Lag'mon
3. MantiAvval map har taomni raqamli satrga aylantirdi, keyin join("\n") ularni yangi qator belgisi bilan uladi. Telegram bot menyu xabarini aynan shunday yig'adi.
O'zingiz to'ldiring. [1, 2, 3].map((x) => x * 10) natijasi — [10, 20, ], uning uzunligi — .
Tekshirib ko'ring:
const a = [4, 9]; const b = a.map((x) => x + 1);dan keyinavabda nima bor?a === bnimaga teng?
Javob
a — [4, 9] (o'zgarmadi), b — [5, 10]. a === b — false: map doim yangi massiv yasaydi, ular ikki xil massiv.
2.4 map o'rtada to'xtamaydi
find mos elementni topishi bilan to'xtardi. map esa doim oxirigacha boradi: callback aniq length marta chaqiriladi. Bu uning va'dasidan kelib chiqadi — har elementga natija kerak, bittasini ham tashlab ketib bo'lmaydi.
const narxlar = [35000, 28000, 30000];
const yangi = narxlar.map((narx, i) => {
console.log(`${i}-element: ${narx}`);
return narx + 2000;
});
console.log(yangi); // [ 37000, 30000, 32000 ]Konsolda:
0-element: 35000
1-element: 28000
2-element: 30000
[ 37000, 30000, 32000 ]Callback ichidagi console.log — faqat kuzatish uchun, xuddi Massivda qidirish darsidagi find tajribasi kabi. Haqiqiy kodda map callback'i faqat qiymat qaytaradi.
break yozib bo'lmaydi: callback — alohida funksiya, sikl esa map ichida yashiringan (Massiv bo'ylab yurish darsidagi forEach bilan bir xil sabab). Erta to'xtash kerak bo'lsa, demak sizga map emas, find, some yoki for...of kerak.
2.5 Nomli callback yoki joyida arrow?
Callback'ni ikki xil berish mumkin. Qisqa va bir martalik bo'lsa — joyida, arrow bilan: narxlar.map((narx) => narx * 2). Uzun bo'lsa yoki bir necha joyda kerak bo'lsa — alohida nomli funksiya qilib, nomini bering: menyu.map(taomQatori).
Nomli funksiyaning uchta foydasi bor:
- O'qiladi.
menyu.map(taomQatori)— "menyuni taom qatorlariga aylantir" deb o'qiladi. Nomdagi so'z callback ichini o'qishdan tezroq tushuntiradi. - Qayta ishlatiladi. Bitta
taomQatorimenyuni ham, "kun taomlari" ni ham chizadi. - Alohida sinaladi. Funksiyani bitta obyekt bilan chaqirib, natijasiga qarash mumkin — butun massivsiz.
Nom qoidasi o'sha: qiymat qaytaradigan funksiya — natija nomi yoki fe'l bilan (taomQatori, narxniHisobla). Callback'ning o'ziga ham bu qoida tegishli: map dan oldin "bu funksiya bitta elementdan nima yasaydi?" deb so'rang — javob uning nomi bo'ladi.
3. Obyektlar massivi bilan map
Real ma'lumot ko'pincha obyektlar massivi: menyu, buyurtmalar, vazifalar. map ular bilan uch xil ish qiladi.
3.1 Bitta maydonni ajratib olish
Menyudan faqat taom nomlari kerak:
const menyu = [
{ nom: "Osh", narx: 35000 },
{ nom: "Lag'mon", narx: 28000 },
{ nom: "Manti", narx: 30000 },
{ nom: "Ko'k choy", narx: 5000 },
];
const nomlar = menyu.map((taom) => taom.nom);
console.log(nomlar.join(", ")); // Osh, Lag'mon, Manti, Ko'k choyObyekt kirdi — satr chiqdi. Bu eng ko'p uchraydigan map: ro'yxatdagi obyektlardan bitta maydon "sug'urib" olinadi.
Bir qatorli callback'ni destructuring bilan ham yozsa bo'ladi: menyu.map(({ nom }) => nom). Parametrda destructuring — Parametrda destructuring darsidagi usul. Qaysi biri o'qishga qulay bo'lsa — shuni tanlang.
Tekshirib ko'ring: Yuqoridagi
menyudanmenyu.map((taom) => taom.narx > 10000)nima qaytaradi? Uzunligi nechta?
Javob
[ true, true, true, false ] — to'rt element. Callback mantiqiy qiymat qaytardi, map esa uni shunchaki yangi massivga qo'ydi. map tanlamaydi: arzon ko'k choy tushib qolmadi, uning o'rnida false turibdi. "Faqat qimmatlarini ol" degan vazifa — filter ning ishi.
3.2 Yangi obyekt yasash
Otabekka kechki aksiya uchun menyu kerak: har taomning eski va yangi narxi. Asl menyuga tegmaslik shart — kassa undan foydalanadi.
const menyu = [
{ nom: "Osh", narx: 35000 },
{ nom: "Manti", narx: 30000 },
];
const aksiya = menyu.map((taom) => ({
...taom,
aksiyaNarxi: taom.narx - taom.narx / 10,
}));
console.log(aksiya);
console.log(menyu[0]);Konsolda:
[
{ nom: 'Osh', narx: 35000, aksiyaNarxi: 31500 },
{ nom: 'Manti', narx: 30000, aksiyaNarxi: 27000 }
]
{ nom: 'Osh', narx: 35000 }Ikki narsaga e'tibor bering:
...taom— eski obyektning hamma xususiyati yangi obyektga ko'chirildi (Spread), keyin yangi maydon qo'shildi.=> ({ ... })— obyekt oddiy qavsga o'ralgan. Arrow funksiyalar darsidagi qoida: qavssiz=> {ni JavaScript funksiya tanasi deb o'ylaydi. Bu xatoni «Ko'p uchraydigan xatolar» bo'limida ko'ramiz.
Oxirgi qator: asl menyu[0] da aksiyaNarxi yo'q. Callback imzosi darsida forEach bilan menyuni buzib qo'ygan edik — map bilan esa yangi obyektlar yasadik.
3.3 Ehtiyot bo'ling: map ham obyektni buzishi mumkin
map yangi massiv yasaydi, lekin ichidagi obyektlarni o'zi nusxalamaydi. Callback obyektni o'zgartirib, o'shani qaytarsa — nima bo'ladi?
const menyu = [{ nom: "Osh", narx: 35000 }];
const aksiya = menyu.map((taom) => {
taom.narx = taom.narx - taom.narx / 10;
return taom;
});
console.log(menyu[0].narx); // 31500
console.log(aksiya[0] === menyu[0]); // trueMassiv yangi, lekin uning ichidagi obyekt — o'sha-o'sha. Callback havola orqali asl obyektni o'zgartirdi (Havola semantikasi). Natijada ikkala massivda ham osh 31 500.
Qoida: map callback'i elementni o'zgartirmasin, yangisini qaytarsin — ({ ...taom, narx: ... }). Callback toza funksiya bo'lsin (Pure funksiya).
3.4 Bitta elementni yangilash (immutable)
Sayoz va chuqur nusxalash darsida savatdagi bitta mahsulotni yangilash uchun avval massiv nusxasini oldik, keyin kerakli o'ringa yangi obyekt qo'ydik. O'sha darsda "qisqaroq usul — map" degan edik. Mana u:
const vazifalar = [
{ id: 1, matn: "Non olish", bajarildi: false },
{ id: 2, matn: "DOM darsini takrorlash", bajarildi: false },
];
const yangilari = vazifalar.map((v) =>
v.id === 2 ? { ...v, bajarildi: true } : v,
);
console.log(yangilari[1].bajarildi); // true
console.log(vazifalar[1].bajarildi); // false
console.log(yangilari[0] === vazifalar[0]); // trueCallback har vazifaga bitta savol beradi: "sen 2-raqamlimisan?" Ha bo'lsa — o'zgargan yangi obyekt qaytadi. Yo'q bo'lsa — eski obyektning o'zi (ternary operator).
Oxirgi qator true — bu xato emas, afzallik. O'zgarmagan vazifa nusxalanmadi, ikkala massivda umumiy qoldi. Asl vazifalar esa butunlay o'z holida.
Bu usulning nomi bor. Immutable yangilash (immutable update) — asl ma'lumotga tegmay, o'zgarishi bor yangi nusxa yasash. Inglizcha "immutable" — "o'zgarmas": eski qiymat o'zgarmaydi, uning o'rniga yangisi paydo bo'ladi. Xuddi daftardagi xatoni o'chirmay, yangi betga to'g'ri variantni yozishdek. React'da holatni aynan shunday yangilaysiz (React — 17-qismda, hozir bilish shart emas).
Tekshirib ko'ring: Yuqoridagi kodda callback
vni emas,{ ...v }ni qaytarsa (o'zgarmagan vazifalar uchun ham), natija qanday farq qiladi?
Javob
Qiymatlar bir xil bo'ladi, lekin yangilari[0] === vazifalar[0] — false. O'zgarmagan vazifa ham keraksiz nusxalanadi. Kichik ro'yxatda farq sezilmaydi, lekin "nima o'zgardi?" degan savolga === endi javob bera olmaydi — har obyekt "yangi" bo'lib ko'rinadi.
3.5 Ichma-ich ma'lumot: map ichida map
Ba'zan har element ichida yana massiv bo'ladi. Masalan, har stolning buyurtmasi — taomlar ro'yxati. Rustam aka oshxonada faqat stol raqami va taom nomlarini ko'rishi kerak:
const stollar = [
{ stol: 3, taomlar: [{ nom: "Osh" }, { nom: "Ko'k choy" }] },
{ stol: 7, taomlar: [{ nom: "Manti" }] },
];
const oshxonaga = stollar.map((s) => ({
stol: s.stol,
nomlar: s.taomlar.map((t) => t.nom),
}));
console.log(oshxonaga);Konsolda:
[
{ stol: 3, nomlar: [ 'Osh', "Ko'k choy" ] },
{ stol: 7, nomlar: [ 'Manti' ] }
]Tashqi map har stolni yangi obyektga aylantiradi. Ichki map shu stolning taomlarini nomlarga aylantiradi. Har qavatda qoida o'sha: nechta kirdi — shuncha chiqdi. Stollar 2 ta — natija ham 2 ta, 3-stolning taomlari 2 ta — nomlari ham 2 ta.
Ikki qavatdan chuqurroq map o'qishni qiyinlashtiradi. Bunday paytda ichki qismni nomli funksiyaga chiqaring: nomlar: taomNomlari(s.taomlar).
4. Obyektni map bilan qayta ishlash
map — massiv metodi, obyektda yo'q. Lekin Obyekt bo'ylab yurish darsida obyektni massivga aylantirib, qayta yig'ishni o'rgangan edik: entries → o'zgartirish → fromEntries. O'sha darsda "map bilan bu bitta qatorga tushadi" degan edik:
const menyu = { osh: 35000, lagmon: 28000, choy: 5000 };
const chegirmali = Object.fromEntries(
Object.entries(menyu).map(([nom, narx]) => [nom, narx * 0.9]),
);
console.log(chegirmali); // { osh: 31500, lagmon: 25200, choy: 4500 }
console.log(menyu); // { osh: 35000, lagmon: 28000, choy: 5000 }Ichkaridan tashqariga o'qing:
Object.entries(menyu)—[["osh", 35000], ...]juftliklar massivi..map(([nom, narx]) => [nom, narx * 0.9])— har juftlik yangi juftlikka aylanadi. Parametrdagi[nom, narx]— juftlikni darhol ikki o'zgaruvchiga ajratadi (Massiv destructuring).Object.fromEntries(...)— yangi juftliklardan yangi obyekt.
08-qismdagi sikl, bo'sh massiv va push kerak bo'lmadi.
5. map va forEach: qaysi biri qachon
Ikkalasi ham har element uchun callback chaqiradi. Farq — natijada:
forEach |
map |
|
|---|---|---|
| Qaytaradi | undefined |
yangi massiv |
| Callback qaytargani | tashlab yuboriladi | yangi massivga tushadi |
| Maqsad | yon ta'sir: chiqarish, DOM | yangi ma'lumot yasash |
Qoida oddiy: natija kerak bo'lsa — map, faqat ish bajarish kerak bo'lsa — forEach.
Ba'zan map ni forEach o'rnida ishlatishadi: taomlar.map((t) => console.log(t)). Kod ishlaydi, lekin map keraksiz [undefined, undefined, ...] massivini yasab, tashlab yuboradi. Eng yomoni — kodni o'qigan odam chalg'iydi: "map ekan, natijasi qayerda ishlatilyapti?" Kodni tekshiradigan vositalar (masalan ESLint, 16-qismda) bunday yozuvni xato deb belgilashi mumkin.
map kerak emas bo'lgan yana uch holat bor. Natija uzunligi boshqacha bo'lishi kerak bo'lsa (ba'zi elementlar tushib qolsin) — filter. Natija massiv emas, bitta son yoki obyekt bo'lsa (masalan jami summa) — reduce. Topish bilan to'xtash kerak bo'lsa — find. Har birini o'z darsida ko'ramiz. Belgi oddiy: "kirganlar soni = chiqqanlar soni va har biri aylanadi" — shundagina map.
Tekshirib ko'ring: Quyidagi ikki vazifaning qaysi biriga
map, qaysi birigaforEachkerak? (a) har mijozga SMS yuborish; (b) mijozlar ro'yxatidan telefon raqamlari ro'yxatini olish.
Javob
(a) — forEach: SMS yuborish — yon ta'sir, natija massivi kerak emas. (b) — map: har mijoz telefon raqamiga aylanadi, natija — yangi massiv.
6. Brauzerda: map bilan elementlar yasash
map faqat son va satr bilan emas, DOM elementlari bilan ham ishlaydi. Callback element yaratib qaytarsa — natija elementlar massivi bo'ladi. Uni spread bilan replaceChildren ga bersa, hammasi bitta amal bilan sahifaga tushadi (Element yaratish, joylash va o'chirish):
<style>
body { margin: 1rem; font: 1rem/1.5 system-ui, sans-serif; }
ul { max-width: 18rem; padding: 0; list-style: none; }
li {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #c9d6cf;
padding-block: 0.25rem;
}
.narx { color: #b4461a; font-variant-numeric: tabular-nums; }
</style>
<h2>«Bahor» menyusi</h2>
<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 royxat = document.getElementById("menyu");
function taomQatori(taom) {
const li = document.createElement("li");
const nom = document.createElement("span");
nom.className = "taom-nomi";
nom.textContent = taom.nom;
const narx = document.createElement("span");
narx.className = "narx";
narx.textContent = `${taom.narx} so'm`;
li.append(nom, narx);
return li;
}
const qatorlar = menyu.map(taomQatori);
royxat.replaceChildren(...qatorlar);
console.log(qatorlar.length);
console.log(royxat.children.length);
</script>Konsolda:
4
4menyu.map(taomQatori) — to'rtta obyekt kirdi, to'rtta li chiqdi. taomQatori ni qavssiz, to'g'ridan-to'g'ri berdik. Bu xavfsiz, chunki u faqat bitta parametr oladi — map beradigan indeks va massiv shunchaki e'tiborsiz qoladi. Matnlar textContent bilan yozildi (XSS xavfi).
"Tahrirlab ko'rish" bilan menyuga yangi obyekt qo'shing — ro'yxat va ikkala son ham o'zi o'zgaradi.
7. Mashhur tuzoq: ["1", "2", "3"].map(parseInt)
Inputdan kelgan satrlarni songa aylantirmoqchimiz. Matn ↔ son darsidagi parseInt ni to'g'ridan-to'g'ri beramiz:
console.log(["1", "2", "3"].map(parseInt)); // [ 1, NaN, NaN ]Faqat birinchisi to'g'ri. Xato yo'q, ogohlantirish yo'q — shunchaki noto'g'ri natija. Nega?
Javob — callback imzosida. map parseInt ni uchta argument bilan chaqiradi: element, indeks, massiv. parseInt esa ikkinchi argumentni radix (sanoq tizimi asosi) deb oladi. Demak indeks radix'ga aylanib qoldi:
| Chaqiruv | Aslida | Natija | Nega |
|---|---|---|---|
| 1-element | parseInt("1", 0) |
1 |
radix 0 — "berilmagan" deb olinadi, o'nlik |
| 2-element | parseInt("2", 1) |
NaN |
1 lik sanoq tizimi yo'q (2 dan 36 gacha) |
| 3-element | parseInt("3", 2) |
NaN |
ikkilik tizimda 3 raqami yo'q |
Yana bir misol buni yaqqol ko'rsatadi:
console.log(["10", "10", "10"].map(parseInt)); // [ 10, NaN, 2 ]Uchinchi "10" ikkilik tizimda o'qildi — bu 2 (Son yozish shakllari).
Ikki tuzatish:
console.log(["1", "2", "3"].map(Number)); // [ 1, 2, 3 ]
const sonlar = ["1", "2", "3"].map((s) => parseInt(s, 10));
console.log(sonlar); // [ 1, 2, 3 ]Number faqat bitta argumentdan foydalanadi — indeks unga xalaqit bermaydi. Ikkinchi usul radix'ni o'zimiz beradi va arrow funksiya indeksni "yutib" qo'yadi. Callback imzosi darsidagi qoidaning eng mashhur namunasi shu: ikkinchi parametri bor funksiyani metodga to'g'ridan-to'g'ri bermang.
Tekshirib ko'ring:
["1.5", "2.5"].map(parseFloat)to'g'ri ishlaydimi?
Javob
Ha: [ 1.5, 2.5 ]. parseFloat faqat bitta parametr oladi — radix'i yo'q (Matn ↔ son). Indeks unga beriladi, lekin e'tiborsiz qoladi. Shunga qaramay, odat sifatida arrow bilan yozish xavfsizroq: keyin kim funksiyani o'zgartirsa ham, kod buzilmaydi.
8. Ko'p uchraydigan xatolar
8.1 Jingalak qavsli callback'da return yo'q
const narxlar = [35000, 28000];
const ikkiPorsiya = narxlar.map((narx) => {
narx * 2;
});
console.log(ikkiPorsiya); // [ undefined, undefined ]Xato xabari yo'q, lekin hamma element undefined. Uzunlik saqlandi — map va'dasini bajardi. Callback esa hech narsa qaytarmadi. Tuzatish: (narx) => narx * 2 yoki { return narx * 2; }.
8.2 Obyektni qavssiz qaytarish
const menyu = [{ nom: "Osh", narx: 35000 }];
console.log(menyu.map((t) => { nom: t.nom })); // [ undefined ]JavaScript { ni funksiya tanasi deb o'qidi. Ichidagi nom: esa obyekt kaliti emas, kamdan-kam ishlatiladigan label bo'lib qoldi (break, continue va label'lar). Natija — undefined. Ikki maydon yozsangiz, kod umuman ishga tushmaydi:
const menyu = [{ nom: "Osh", narx: 35000 }];
console.log(menyu.map((t) => { nom: t.nom, narx: t.narx }));SyntaxError: Unexpected token ':'Tarjimasi: "kutilmagan belgi: :". JavaScript ikkinchi narx: ni hech qanday qoidaga moslay olmadi. Tuzatish: obyektni qavsga o'rang — (t) => ({ nom: t.nom, narx: t.narx }).
8.3 Natijani saqlamaslik
const narxlar = [35000, 28000];
narxlar.map((narx) => narx * 2);
console.log(narxlar); // [ 35000, 28000 ]"Narxlar ikki baravar bo'lishi kerak edi-ku!" map aslini o'zgartirmaydi — u yangi massivni qaytaradi. Qaytgan qiymat hech qayerga yozilmadi va yo'qoldi. Tuzatish: const ikkiPorsiya = narxlar.map(...).
8.4 NodeList da map yo'q
querySelectorAll qaytaradigan NodeList da forEach bor, lekin map va filter yo'q (Elementlarni tanlash). document.querySelectorAll("li").map(...) yozsangiz, Chrome konsolida:
Uncaught TypeError: document.querySelectorAll(...).map is not a functionTarjimasi: "...map funksiya emas" — bunday metod umuman yo'q. Tuzatish: avval haqiqiy massivga aylantiring — [...document.querySelectorAll("li")].map(...).
9. Mashqlar
1-mashq (oson): Chek qatorlari
narxlar massividan map bilan 35000 so'm ko'rinishidagi satrlar massivini yasang va uni join(" | ") bilan chiqaring.
const narxlar = [35000, 28000, 5000];Yechim
const narxlar = [35000, 28000, 5000];
const yozuvlar = narxlar.map((narx) => `${narx} so'm`);
console.log(yozuvlar.join(" | "));Konsolda:
35000 so'm | 28000 so'm | 5000 so'mSon kirdi — satr chiqdi. Uzunlik o'zgarmadi: 3 ta.
2-mashq (o'rta): Buyurtma summasi
Ofitsiant Otabek buyurtmalarni faqat taom nomi va soni bilan yozadi. Narx menyuda. Har buyurtmaga summa maydonini qo'shib, yangi massiv yasang.
Ishora: callback ichida narxni find bilan menyudan toping. Yangi obyekt — ({ ...b, summa: ... }).
const menyu = [
{ nom: "Osh", narx: 35000 },
{ nom: "Manti", narx: 30000 },
{ nom: "Ko'k choy", narx: 5000 },
];
const buyurtmalar = [
{ taom: "Osh", soni: 2 },
{ taom: "Ko'k choy", soni: 3 },
];Yechim
const menyu = [
{ nom: "Osh", narx: 35000 },
{ nom: "Manti", narx: 30000 },
{ nom: "Ko'k choy", narx: 5000 },
];
const buyurtmalar = [
{ taom: "Osh", soni: 2 },
{ taom: "Ko'k choy", soni: 3 },
];
const hisoblangan = buyurtmalar.map((b) => {
const taom = menyu.find((t) => t.nom === b.taom);
return { ...b, summa: taom.narx * b.soni };
});
console.log(hisoblangan);Konsolda:
[
{ taom: 'Osh', soni: 2, summa: 70000 },
{ taom: "Ko'k choy", soni: 3, summa: 15000 }
]Callback jingalak qavsli, chunki ichida ikki qadam bor — shuning uchun return yozdik. Ikki HOF metod bir-birining ichida: map callback'i ichida find. Asl buyurtmalar o'zgarmadi.
3-mashq (qiyin): Savatda sonni o'zgartirish
sonniOzgartir(savat, nom, yangiSoni) funksiyasini yozing. U savatni o'zgartirmasdan, kerakli mahsulot soni yangilangan yangi savat qaytarsin. O'zgarmagan mahsulotlar eski obyektlar bo'lib qolsin. Uchta narsani tekshiring: yangi son, asl savat va ===.
Yechim
function sonniOzgartir(savat, nom, yangiSoni) {
return savat.map((m) =>
m.nom === nom ? { ...m, soni: yangiSoni } : m,
);
}
const savat = [
{ nom: "Osh", soni: 1 },
{ nom: "Manti", soni: 2 },
];
const yangi = sonniOzgartir(savat, "Manti", 5);
console.log(yangi[1].soni); // 5
console.log(savat[1].soni); // 2
console.log(yangi[0] === savat[0]); // true
console.log(yangi === savat); // falseFunksiya toza: bir xil argumentga doim bir xil natija va hech narsani buzmaydi. Bunday funksiyani sinash oson — uchta console.log uni to'liq tekshirdi.
4-mashq: Vazifalar qadami — qatorlarni map bilan yasang
refactor/hof-metodlar branch'ida davom etamiz. render() ning boshi hozir shunday:
const quti = document.createDocumentFragment();
for (const vazifa of korinadiganlar()) {
if (vazifa.id === holat.tahrirId) {
quti.append(tahrirQatori(vazifa));
} else {
quti.append(oddiyQator(vazifa));
}
}
royxat.replaceChildren(quti);Uni ikki qismga ajrating:
qatorYasa(vazifa)— vazifadan tayyorliqaytaradigan funksiya: tahrirdagisi uchuntahrirQatori, qolgani uchunoddiyQator.render()da —korinadiganlar()nimapbilanlilarga aylantirib,replaceChildrenga bering.
Xulq o'zgarmasin.
Yechim
Yangi funksiya — "4. Chizish" bo'limiga, tahrirQatori dan keyin:
function qatorYasa(vazifa) {
if (vazifa.id === holat.tahrirId) {
return tahrirQatori(vazifa);
}
return oddiyQator(vazifa);
}render() ning boshi endi bitta qator:
royxat.replaceChildren(...korinadiganlar().map(qatorYasa));Nima o'zgardi:
DocumentFragmentkerak emas.replaceChildren(...)ko'p elementni bitta amal bilan qo'yadi. DOM standartiga ko'ra brauzer ularni ichkarida o'zi fragmentga yig'adi — sahifa avvalgidek bir marta qayta chiziladi (Ko'p elementni samarali chizish).qatorYasa— toza funksiya. Uholatni o'qiydi, lekin hech narsani o'zgartirmaydi: vazifa kiradi,lichiqadi. Bu —mapcallback'iga aynan kerakli shakl.- Qavssiz berish xavfsiz.
mapqatorYasani(vazifa, index, array)bilan chaqiradi, u esa faqat birinchisini oladi. Callback imzosi darsidagi tekshiruvni qildik: ikkinchi parametr yo'q — tuzoq yo'q. - Bo'sh ro'yxat. Filtr hech narsa qoldirmasa,
mapbo'sh massiv qaytaradi,replaceChildren()argumentsiz chaqiriladi va ro'yxatni tozalaydi — avvalgidek.
Xulq o'zgarmaganini tekshiring:
- Sahifa ochilganda — uch vazifa, "2 ta vazifa qoldi".
- «Tahrirlash» — qator maydonga aylanadi,
Esc— qaytadi, fokus «Tahrirlash» da. - «Faol» filtrida ikkala vazifani belgilang — "Faol vazifa yo'q." chiqadi, fokus "Ro'yxat" sarlavhasida.
Commit: Render: qatorlarni map bilan yasa.
10. Real ishda
- React. Ro'yxat chizishning yagona asosiy usuli:
vazifalar.map((v) => <li>{v.matn}</li>). Bugungimenyu.map(taomQatori)— aynan shu g'oya, faqat qo'lda. - API javoblari. Serverdan kelgan ma'lumot ko'pincha boshqa shaklda:
created_at,user_name. Uni ilovaga kerakli ko'rinishgamapbilan aylantirishadi — bu qatlam "mapper" deb ham ataladi. - Immutable yangilash.
list.map((x) => x.id === id ? { ...x, ... } : x)— React, Redux va boshqa holat kutubxonalarida har kuni yoziladigan qator. - Hisobotlar. Buxgalteriya jadvalidagi har qatorga yangi ustun qo'shish — "QQS bilan narx", "dollarda narx" — dasturda
mapbilan qilinadi. Jadval satrlari soni o'zgarmaydi, har satr yangi maydon oladi — 2-mashqdagisummaaynan shunday. - Intervyu.
["1", "2", "3"].map(parseInt)— klassik savol. Endi siz faqat javobni emas, sababini ham bilasiz: callback imzosi va radix.
Xulosa
maphar elementni callback orqali aylantiradi va yangi massiv qaytaradi.- Yangi massiv — aslidek uzunlikda va tartibda; asl massiv o'zgarmaydi.
- Obyekt qaytarishda qavs:
=> ({ ... }). Callback obyektni o'zgartirmasin — yangisini qaytarsin. map((x) => x.id === id ? { ...x, ... } : x)— bitta elementni immutable yangilash.- Natija kerak —
map, faqat ish bajarish —forEach.mapo'rtada to'xtamaydi va element tanlamaydi. - Uzun callback'ni nomli funksiyaga chiqaring:
menyu.map(taomQatori)o'zi o'qiladi. - Ikkinchi parametri bor funksiyani (
parseInt) to'g'ridan-to'g'ri bermang — arrow bilan o'rang.
Keyingi dars: filter: shart bo'yicha tanlash — massivdan faqat kerakli elementlarni tanlaymiz va vazifalar dagi korinadiganlar ni bitta qatorga tushiramiz.
Manbalar
- MDN: "Array.prototype.map()" — developer.mozilla.org
- MDN: "Element: replaceChildren() method" — developer.mozilla.org
- DOM Standard: "converting nodes into a node" — dom.spec.whatwg.org
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!