Mundarija (37)
- Bu darsda
- 1. Nega bu kerak?
- 2. Map yaratish va asosiy metodlar
- 2.1 Birinchi Map
- 2.2 Oltita asosiy a'zo
- 2.3 Boshlang'ich juftliklar bilan yaratish
- 2.4 get dagi undefined — ikki ma'no
- 3. Kalit — istalgan tur
- 3.1 Son satr emas
- 3.2 Kalitlar qanday solishtiriladi
- 3.3 Obyekt kalit: havola bo'yicha
- 4. Map bo'ylab yurish
- 4.1 for...of va juftliklar
- 4.2 keys, values, entries
- 4.3 forEach — tartibi teskari imzo
- 4.4 Map bilan sanash — qadamma-qadam
- 5. Map ↔ obyekt va JSON
- 5.1 Ikki tomonga aylantirish
- 5.2 JSON Map ni bilmaydi
- 6. Hujumchi nigohi: kalitlar tashqaridan kelganda
- 7. Map.groupBy — endi to'liq tushunarli
- 8. Yangi imkoniyat: getOrInsert
- 9. Obyekt yoki Map?
- 10. Ko'p uchraydigan xatolar
- 10.1 Kvadrat qavs bilan yozish
- 10.2 Obyekt kalitni yangi obyekt bilan qidirish
- 10.3 Son kalitni satr bilan o'qish
- 10.4 forEach da parametrlar tartibi
- 10.5 Map ni JSON'ga to'g'ridan-to'g'ri yozish
- 11. Mashqlar
- 1-mashq (oson): Stollar bandligi
- 2-mashq (o'rta): Eng ko'p so'ralgan taom
- 3-mashq (qiyin): Eng ko'p tushum bergan stol — Map.groupBy bilan
- 4-mashq: Vazifalar qadami — teglar hisobi
- 12. Real ishda
- Xulosa
- Manbalar
JavaScript Map: istalgan turdagi kalitli lug'at
Qisqacha:
Map— kalit-qiymat juftliklarini saqlaydigan maxsus to'plam. Oddiy obyektdan farqi: kalit istalgan turda bo'ladi (son, boolean, hatto obyekt) va satrga aylantirilmaydi, juftliklar qo'shilgan tartibda turadi, soni esasizeda tayyor. Ishlatish:const narxlar = new Map(); narxlar.set("osh", 35000); narxlar.get("osh").
Bu darsda
Mapyaratib,set,get,has,delete,clearvasizebilan ishlay olasiz.- Son, boolean va obyektni kalit qila olasiz va ularning tuzog'ini bilasiz.
Mapbo'ylabfor...ofvaforEachbilan yura olasiz, uni massiv va obyektga aylantira olasiz.- Qachon oddiy obyekt, qachon
Mapkerakligini tanlay olasiz. vazifalarga teglar hisobini qo'shasiz.
Oldin bilishingiz kerak: Obyekt: kalit-qiymat juftliklari, for...of va for...in, reduce, Guruhlash: Object.groupBy va Map.groupBy, Prototype pollution, Closure amaliyotda.
1. Nega bu kerak?
08-qismdan beri lug'at kerak bo'lsa, oddiy obyekt olardik: { osh: 35000, manti: 30000 }. Bu ko'p hollarda yaxshi ishlaydi. Lekin shu qismda obyekt bir necha marta "qoqildi":
- Guruhlash darsida stol raqami
3kalit bo'lganda"3"satriga aylandi. Keyin uniNumberbilan qaytarishga to'g'ri keldi. - O'sha darsda
"constructor"degan teg butun dasturni to'xtatdi: obyekt bu kalitni prototipdan meros olgan edi. - Prototype pollution darsida
__proto__kaliti obyektning prototipini almashtirib yubordi. - Closure amaliyotda darsidagi
keshlanganfunksiya3va"3"ni bitta kalit deb o'yladi.
Hammasining ildizi bitta. Obyekt aslida lug'at uchun yaratilmagan: u dasturdagi narsani (taom, foydalanuvchi, vazifa) tasvirlash uchun. Kalitlari doim satr va uning prototipi bor.
Shu muammolar uchun JavaScript'da maxsus to'plam bor — Map. Hayotdan o'xshatish: kiyim saqlash xonasi (garderob). Siz paltoni topshirasiz, raqamli jeton olasiz. Jeton raqam bo'ladimi, rangli plastinkami — farqi yo'q. Xodim uni hech narsaga "aylantirmaydi", paltoni aynan shu jetonga beradi. Xonada boshqa birovning eski paltolari ham "meros" bo'lib osilib turmaydi.
2. Map yaratish va asosiy metodlar
2.1 Birinchi Map
Map — kalit-qiymat juftliklari to'plami, unda kalit istalgan turdagi qiymat bo'lishi mumkin. Map — JavaScript'ga tayyor qo'shib qo'yilgan klass. Shuning uchun u o'zingiz yozgan klasslar kabi new bilan yaratiladi:
const narxlar = new Map();
narxlar.set("osh", 35000);
narxlar.set("manti", 30000);
console.log(narxlar.get("osh")); // 35000
console.log(narxlar.size); // 2
console.log(narxlar);Konsolda:
35000
2
Map(2) { 'osh' => 35000, 'manti' => 30000 }Node Map ni o'ziga xos ko'rinishda chiqaradi: qavs oldida Map(2) — juftliklar soni, ichida esa kalit => qiymat strelkalari. Brauzer konsoli Map(2) {'osh' => 35000, 'manti' => 30000} deb ko'rsatadi — ma'nosi bir xil.
Nuqta bilan yozish (narxlar.osh) bu yerda ishlamaydi. Map da juftlik faqat metodlar orqali o'qiladi va yoziladi. Nega shunday — «Ko'p uchraydigan xatolar» bo'limida ko'ramiz.
2.2 Oltita asosiy a'zo
Jadvalda m — biror Map, k — kalit, q — qiymat:
| Yozuv | Nima qiladi | Qaytaradi |
|---|---|---|
m.set(k, q) |
juftlik qo'shadi yoki qiymatni yangilaydi | Map ning o'zi |
m.get(k) |
kalit bo'yicha qiymatni oladi | qiymat yoki undefined |
m.has(k) |
kalit bormi? | true / false |
m.delete(k) |
juftlikni o'chiradi | o'chdimi: true / false |
m.clear() |
hammasini o'chiradi | undefined |
m.size |
juftliklar soni (xususiyat, metod emas) | son |
Hammasini bitta misolda ko'ramiz. Otabek stollar bandligini yozib boradi:
const stollar = new Map();
stollar.set(1, "Dilshod aka").set(3, "Malika").set(5, "Bobur");
console.log(stollar.size); // 3
console.log(stollar.has(3)); // true
console.log(stollar.delete(3)); // true
console.log(stollar.delete(3)); // false
console.log(stollar.get(3)); // undefined
stollar.set(1, "Nodira");
console.log(stollar.get(1)); // Nodira
stollar.clear();
console.log(stollar.size); // 0Birinchi qatorga qarang: set uch marta zanjir bo'lib chaqirildi. Bu mumkin, chunki set Map ning o'zini qaytaradi. Ikkinchi delete(3) esa false berdi — o'chiradigan narsa qolmagan edi. set(1, ...) mavjud kalitga yangi qiymat yozdi, yangi juftlik qo'shmadi.
size — oddiy xususiyat, qavssiz yoziladi. Obyektda kalitlar sonini bilish uchun Object.keys(obj).length yozardik. Bu har safar vaqtinchalik massiv yasaydi. Map esa sonini doim tayyor saqlaydi.
2.3 Boshlang'ich juftliklar bilan yaratish
new Map() ga juftliklar massivini bersangiz, Map darhol to'ladi. Har juftlik — ikki elementli massiv: [kalit, qiymat].
const menyu = new Map([
["osh", 35000],
["lag'mon", 28000],
["ko'k choy", 5000],
]);
console.log(menyu.get("lag'mon")); // 28000Shakl tanish: Object.entries aynan shunday juftliklar massivini qaytaradi. Demak obyektdan Map yasash — bitta qator: new Map(Object.entries(obj)).
2.4 get dagi undefined — ikki ma'no
const qoldiq = new Map([["osh", undefined]]);
console.log(qoldiq.get("osh")); // undefined
console.log(qoldiq.get("manti")); // undefined
console.log(qoldiq.has("osh")); // true
console.log(qoldiq.has("manti")); // falseget ikkala holatda undefined qaytardi. Lekin birinchisida kalit bor, qiymati undefined. Ikkinchisida kalitning o'zi yo'q. Farqni faqat has ko'rsatadi. Qoida: "bormi?" savoli uchun doim has ni ishlating.
Tekshirib ko'ring:
new Map().set("a", 1).set("b", 2).sizenimaga teng?
Javob
2. new Map() bo'sh to'plam yaratadi. Birinchi set uni qaytaradi, ikkinchi set shu to'plamga yana bitta juftlik qo'shadi va yana uni qaytaradi. Oxirida .size — ikki juftlik.
3. Kalit — istalgan tur
3.1 Son satr emas
Obyektda obj[3] va obj["3"] — bitta kalit. Map da — ikki xil:
const m = new Map();
m.set(3, "son");
m.set("3", "satr");
m.set(true, "boolean");
console.log(m.size); // 3
console.log(m.get(3)); // son
console.log(m.get("3")); // satr
console.log(m.get(true)); // booleanKalit qanday bergan bo'lsangiz, shunday saqlanadi. Bu foydali, lekin ehtiyot bo'lish kerak. Forma maydonidan kelgan qiymat doim satr (Forma qiymatlarini o'qish). Stol raqami son bilan saqlangan bo'lsa, stollar.get(input.value) undefined qaytaradi. Kalitni avval kerakli turga keltiring: stollar.get(Number(input.value)).
3.2 Kalitlar qanday solishtiriladi
Map ikki kalitni deyarli === kabi solishtiradi. Bitta farqi bor: NaN o'ziga teng hisoblanadi. Bu qoidaning nomi — SameValueZero, uni Tenglik operatorlari darsida includes orqali ko'rgan edingiz. 0 va -0 ham bitta kalit.
const m = new Map([[NaN, "son emas"]]);
m.set(0, "nol");
console.log(m.get(NaN)); // son emas
console.log(m.get(-0)); // nol3.3 Obyekt kalit: havola bo'yicha
Endi Map ning eng kuchli imkoniyati. Kalit obyekt bo'lishi mumkin. Guruhlash darsida taksi safarlarini haydovchi obyekti bo'yicha guruhlagan edik. Endi bu to'g'ridan-to'g'ri:
const shuhrat = { ism: "Shuhrat" };
const olim = { ism: "Olim" };
const safarlar = new Map();
safarlar.set(shuhrat, 2);
safarlar.set(olim, 5);
console.log(safarlar.get(shuhrat)); // 2
console.log(safarlar.size); // 2Oddiy obyektga shunday yozsangiz, ikkala haydovchi ham "[object Object]" satriga aylanib, bitta kalitga tushardi. Map esa obyektning o'zini kalit qiladi.
Lekin bu yerda bitta muhim tuzoq bor. Obyektlar ichidagi ma'lumot bo'yicha emas, havola bo'yicha solishtiriladi (Havola semantikasi):
const safarlar = new Map();
safarlar.set({ ism: "Shuhrat" }, 2);
console.log(safarlar.get({ ism: "Shuhrat" })); // undefinedIkki { ism: "Shuhrat" } — tashqi ko'rinishi bir xil, lekin xotirada ikki alohida obyekt. get boshqa obyekt bilan qidirdi va hech narsa topmadi. Obyekt kalitdan foydalanish uchun aynan o'sha obyektning havolasi kerak — odatda u o'zgaruvchida yoki boshqa ro'yxatda saqlanadi.
Tekshirib ko'ring:
const m = new Map([[[1], "a"]]);—m.get([1])nima qaytaradi?
Javob
undefined. Massiv ham obyekt. Kalit sifatida berilgan [1] va get ichidagi [1] — ikki xil massiv, havolalari har xil. Massivni kalit qilish kerak bo'lsa, uni avval o'zgaruvchiga oling va o'sha o'zgaruvchi bilan ishlang.
4. Map bo'ylab yurish
4.1 for...of va juftliklar
Map ni for...of bilan aylanish mumkin. Har qadamda [kalit, qiymat] juftligi keladi — uni darhol massiv destructuring bilan ochamiz:
const menyu = new Map([
["osh", 35000],
["manti", 30000],
["ko'k choy", 5000],
]);
for (const [taom, narx] of menyu) {
console.log(`${taom}: ${narx} so'm`);
}Konsolda:
osh: 35000 so'm
manti: 30000 so'm
ko'k choy: 5000 so'mJuftliklar qo'shilgan tartibda keldi. Bu Map ning kafolati. Obyektda esa butun songa o'xshash kalitlar doim oldinga chiqib ketardi (Obyekt bo'ylab yurish):
const obyekt = { b: 1, 2: 1, a: 1, 1: 1 };
const xarita = new Map([["b", 1], [2, 1], ["a", 1], [1, 1]]);
console.log(Object.keys(obyekt)); // [ '1', '2', 'b', 'a' ]
console.log([...xarita.keys()]); // [ 'b', 2, 'a', 1 ]Mavjud kalitga qayta set qilish tartibni o'zgartirmaydi. O'chirib, keyin qo'shsangiz — juftlik oxiriga o'tadi.
for...of nega massivda ham, satrda ham, Map da ham ishlaydi? Ularning hammasi bitta umumiy kelishuvga amal qiladi. Uni Iteratsiya protokoli darsida ochamiz — hozir bilish shart emas.
4.2 keys, values, entries
Faqat kalitlar yoki faqat qiymatlar kerak bo'lsa — uchta metod bor:
const menyu = new Map([
["osh", 35000],
["manti", 30000],
]);
console.log(menyu.keys());
console.log([...menyu.keys()]);
console.log([...menyu.values()]);
console.log([...menyu.entries()]);Konsolda:
[Map Iterator] { 'osh', 'manti' }
[ 'osh', 'manti' ]
[ 35000, 30000 ]
[ [ 'osh', 35000 ], [ 'manti', 30000 ] ]Birinchi qatorga e'tibor bering: keys() massiv emas, [Map Iterator] qaytardi. Iterator — elementlarni bittadan beradigan maxsus obyekt; unda map yoki filter yo'q. Massiv kerak bo'lsa — spread yoki Array.from bilan aylantiring. [...menyu] ham entries() bilan bir xil natija beradi.
4.3 forEach — tartibi teskari imzo
Map da forEach metodi ham bor. Lekin callback imzosi massivdagidan farq qiladi:
const menyu = new Map([["osh", 35000]]);
menyu.forEach((narx, taom, hammasi) => {
console.log(taom, narx, hammasi.size);
});Konsolda:
osh 35000 1Birinchi parametrga qiymat, ikkinchisiga kalit tushadi. Nega teskari? Massivdagi forEach bilan bir xil bo'lishi uchun. U yerda ham birinchisi — qiymat (element), ikkinchisi — uning "manzili" (indeks). Map da manzil o'rnida kalit turadi. Kalitni birinchi o'ringa kutib, (taom, narx) deb yozish — tez-tez uchraydigan xato. Shuning uchun ko'p dasturchilar for...of + destructuring'ni afzal ko'radi: unda tartib ko'zga ko'rinib turadi.
4.4 Map bilan sanash — qadamma-qadam
Map ning eng ko'p uchraydigan ishi — sanash. Kunlik buyurtmalardagi har taom necha marta so'ralgan? Keyingi tugmasini bosib, sanoq ichida nima bo'layotganini kuzating:
To'rtinchi qator — sanashning butun siri: "bor qiymatni ol, yo'q bo'lsa 0 deb ol, bittaga oshirib yoz". ?? operatori undefined ni 0 ga almashtiradi.
O'zingiz to'ldiring. ["a", "b", "a", "a"] ni shu usulda sanasak, sanoq.get("a") — [:3], sanoq.size esa — [:2].
5. Map ↔ obyekt va JSON
5.1 Ikki tomonga aylantirish
const menyu = { osh: 35000, manti: 30000 };
const xarita = new Map(Object.entries(menyu));
xarita.set("ko'k choy", 5000);
const yana = Object.fromEntries(xarita);
console.log(yana);Konsolda:
{ osh: 35000, manti: 30000, "ko'k choy": 5000 }Object.fromEntries — Object.entries ning teskarisi (Object.* metodlari). U har qanday juftliklar to'plamini, shu jumladan Map ni, obyektga aylantiradi. Faqat esda tuting: obyektga o'tganda son va obyekt kalitlar yana satrga aylanadi.
5.2 JSON Map ni bilmaydi
JSON chuqur darsidagi jadvalni eslang:
const menyu = new Map([["osh", 35000]]);
console.log(JSON.stringify(menyu)); // {}
console.log(JSON.stringify([...menyu])); // [["osh",35000]]
const obyekt = Object.fromEntries(menyu);
console.log(JSON.stringify(obyekt)); // {"osh":35000}JSON.stringify Map ni bo'sh obyekt {} qilib yozdi — xatosiz, ma'lumot jimgina yo'qoldi. Saqlash yoki serverga yuborishdan oldin Map ni massivga yoki obyektga aylantiring. Kalitlar oddiy satr bo'lsa — obyekt qulay. Son yoki boolean kalitlar saqlanishi kerak bo'lsa — juftliklar massivi: uni o'qigach new Map(JSON.parse(matn)) bilan qayta tiklaysiz.
6. Hujumchi nigohi: kalitlar tashqaridan kelganda
Prototype pollution darsida hujumchi __proto__ kalitini yuborib, obyektning prototipini o'zgartirgan edi. Kalitlar foydalanuvchidan keladigan joylar xavfli: teglar, so'z sanog'i, URL parametrlari, forma maydonlari nomlari.
Oddiy obyekt va Map ni bir xil hujumli kalit bilan solishtiramiz:
const obyekt = {};
obyekt["__proto__"] = { admin: true };
console.log(obyekt.admin); // true
console.log(Object.keys(obyekt)); // []
const xarita = new Map();
xarita.set("__proto__", { admin: true });
console.log(xarita.size); // 1
console.log(xarita.get("admin")); // undefinedObyektda __proto__ oddiy kalit bo'lib yozilmadi. U prototipni almashtirdi: obyekt.admin endi true, Object.keys esa hech narsa ko'rmaydi. Map da esa "__proto__" — shunchaki bitta satr kalit, boshqalardan farqi yo'q.
Meros kalitlar bilan ham shunday:
const sanoq = {};
console.log(sanoq["constructor"]); // [Function: Object]
const xarita = new Map();
console.log(xarita.get("constructor")); // undefinedMap da prototipdan meros kelgan juftliklar yo'q — faqat siz set qilgan narsa bor. Object.create va prototipal meros darsidagi Object.create(null) ham bu muammoni hal qiladi. Lekin Map qo'shimcha ravishda istalgan turdagi kalit, size va kafolatlangan tartibni beradi. Qoida: kalitlari tashqaridan keladigan lug'at — Map.
7. Map.groupBy — endi to'liq tushunarli
Guruhlash darsida Map.groupBy ni ko'rgan edik, lekin Map hali o'tilmagan edi. Endi uning natijasini to'liq o'qiy olamiz:
const menyu = [
{ nom: "Osh", narx: 35000 },
{ nom: "Ko'k choy", narx: 5000 },
{ nom: "Lag'mon", narx: 28000 },
];
const guruhlar = Map.groupBy(menyu, (t) => t.narx > 20000);
for (const [qimmatmi, taomlar] of guruhlar) {
console.log(qimmatmi, taomlar.map((t) => t.nom));
}Konsolda:
true [ 'Osh', "Lag'mon" ]
false [ "Ko'k choy" ]Natija — oddiy Map. Kalitlar haqiqiy true va false, har guruh — massiv. O'sha darsning 3-mashqida stol raqamini Number bilan qaytargan edik. Bugungi 3-mashqda shu masalani Map.groupBy bilan yechamiz — Number kerak bo'lmaydi.
8. Yangi imkoniyat: getOrInsert
Sanash qolipida har safar ikki qadam yozamiz: get va set. Shu ish uchun Map ga ikki yangi metod qo'shildi:
m.getOrInsert(kalit, qiymat)— kalit bo'lsa, qiymatini qaytaradi. Bo'lmasa, berilgan qiymatni yozadi va uni qaytaradi.m.getOrInsertComputed(kalit, callback)— xuddi shunday, lekin yangi qiymatni faqat kerak bo'lganda callback hisoblaydi. Qiymatni yasash qimmat bo'lsa (masalan, katta massiv) — shunisi.
Guruhlash bilan ko'rinishi:
const guruhlar = new Map();
for (const t of menyu) {
guruhlar.getOrInsert(t.tur, []).push(t);
}Bu metodlar juda yangi. Baseline ma'lumotiga ko'ra ular Chrome va Edge 145, Firefox 144, Safari 26.2 da bor. 2026-yil 14-fevraldan ular Baseline'ning "yangi" (newly available) darajasida. Ya'ni hamma asosiy brauzerning eng so'nggi versiyasida bor, lekin yangilanmagan telefonlarda hali yo'q. Node 24 da esa umuman yo'q — sinab ko'rdik:
TypeError: m.getOrInsert is not a functionTarjimasi: "m.getOrInsert — funksiya emas". Metod yo'q, demak m.getOrInsert — undefined, uni chaqirib bo'lmaydi. Shuning uchun bu kursda hozircha eski, har joyda ishlaydigan shaklni yozamiz:
const menyu = [
{ nom: "Osh", tur: "taom" },
{ nom: "Choy", tur: "ichimlik" },
{ nom: "Manti", tur: "taom" },
];
const guruhlar = new Map();
for (const t of menyu) {
if (!guruhlar.has(t.tur)) {
guruhlar.set(t.tur, []);
}
guruhlar.get(t.tur).push(t.nom);
}
console.log(guruhlar);Konsolda:
Map(2) { 'taom' => [ 'Osh', 'Manti' ], 'ichimlik' => [ 'Choy' ] }Real loyihada kodni qaysi muhitda ishlashiga qarab tanlaysiz: zamonaviy brauzerlar uchun getOrInsert, Node 24 va eski telefonlar uchun — has + set.
9. Obyekt yoki Map?
Ikkalasi ham lug'at bo'la oladi. Tanlash uchun sxemadagi savollarga yuqoridan pastga javob bering:
flowchart TD
A{"Kalitlar oldindan ma'lummi?<br/>(nom, narx, id)"}
A -- "ha, bu narsa tavsifi" --> O["Oddiy obyekt"]
A -- "yo'q, ma'lumot bilan keladi" --> B{"Kalit satrmi?"}
B -- "son, boolean, obyekt" --> M["Map"]
B -- "satr" --> C{"Tashqaridan keladimi<br/>yoki tez-tez o'chiriladimi?"}
C -- "ha" --> M
C -- "yo'q" --> D{"JSON'ga ko'p<br/>yoziladimi?"}
D -- "ha" --> O
D -- "yo'q" --> MQisqasi:
- Obyekt — bitta narsaning tavsifi:
{ id, matn, bajarildi }. Kalitlar kod yozilganda ma'lum, nuqta bilan o'qiladi, JSON'ga to'g'ridan-to'g'ri yoziladi. Map— to'plam: kalitlar dastur ishlaganda paydo bo'ladi va yo'qoladi. Sanoqlar, keshlar, "id → obyekt" jadvallari, teglar.
Tezlik haqida bir gap. V8 (Chrome va Node'da JavaScript'ni bajaradigan dastur — dvigatel) Map ni tez-tez qo'shish va o'chirish uchun moslagan. Obyekt esa shakli o'zgarmaydigan "tavsif" sifatida tez. Kichik ma'lumotda farq sezilmaydi — avval ma'no bo'yicha tanlang.
Tekshirib ko'ring: Telegram bot har foydalanuvchining xabarlar sonini sanaydi. Kalit — foydalanuvchi id raqami (son). Obyektmi yoki
Map?
Javob
Map. Kalitlar oldindan ma'lum emas (yangi foydalanuvchilar keladi), kalit — son, uni satrga aylantirmaslik qulay. Bundan tashqari foydalanuvchi soni size da tayyor.
10. Ko'p uchraydigan xatolar
10.1 Kvadrat qavs bilan yozish
const narxlar = new Map();
narxlar["osh"] = 35000;
console.log(narxlar.size); // 0
console.log(narxlar.get("osh")); // undefined
console.log(narxlar); // Map(0) { osh: 35000 }Xato xabari yo'q, lekin juftlik qo'shilmadi. Map ham obyekt, shuning uchun narxlar["osh"] = ... unga oddiy xususiyat yozdi. Node buni Map(0) { osh: 35000 } deb ko'rsatdi: 0 — juftliklar soni, osh: 35000 — strelkasiz, ya'ni oddiy xususiyat. Tuzatish: faqat set va get.
10.2 Obyekt kalitni yangi obyekt bilan qidirish
«Obyekt kalit: havola bo'yicha» bo'limidagi get({ ism: "Shuhrat" }) — undefined. Tuzatish: kalitni o'zgaruvchida saqlang yoki kalit sifatida id kabi primitivni ishlating.
10.3 Son kalitni satr bilan o'qish
stollar.set(3, ...) keyin stollar.get("3") — undefined. Formadan, URL'dan, dataset dan keladigan qiymatlar doim satr. Tuzatish: get(Number(qiymat)) yoki kalitni boshidan satr qilib saqlang — muhimi, bir xil tur.
10.4 forEach da parametrlar tartibi
map.forEach((kalit, qiymat) => ...) — nomlar teskari: birinchi parametrga qiymat tushadi. Tuzatish: (qiymat, kalit) yoki for (const [kalit, qiymat] of map).
10.5 Map ni JSON'ga to'g'ridan-to'g'ri yozish
JSON.stringify(map) — "{}". Tuzatish: [...map] yoki Object.fromEntries(map).
11. Mashqlar
1-mashq (oson): Stollar bandligi
Bo'sh Map yarating. Unga uch stolni yozing: 2-stol — "Dilshod aka", 4-stol — "Nodira", 7-stol — "Bobur" (stol raqami — son). So'ng: 4-stol bandmi (has), 2-stolda kim (get), 7-stol bo'shadi (delete), nechta stol band (size) — har birini konsolga chiqaring.
Yechim
const band = new Map();
band.set(2, "Dilshod aka").set(4, "Nodira").set(7, "Bobur");
console.log(band.has(4)); // true
console.log(band.get(2)); // Dilshod aka
band.delete(7);
console.log(band.size); // 2set Map ni qaytargani uchun uchalasini zanjir qildik. Kalitlar — son. band.has("4") deb yozsangiz, false chiqardi.
2-mashq (o'rta): Eng ko'p so'ralgan taom
Kunlik buyurtmalar ro'yxati berilgan. Map bilan har taomni sanang, so'ng eng ko'p so'ralganini toping. Natija: osh — 3 marta.
Ishora: sanash — «Map bilan sanash» bo'limidagi qolip. Eng kattasini topish uchun [...sanoq] ni reduce yoki toSorted bilan ishlang.
const buyurtmalar = ["osh", "manti", "osh", "choy", "manti", "osh"];Yechim
const buyurtmalar = ["osh", "manti", "osh", "choy", "manti", "osh"];
const sanoq = new Map();
for (const taom of buyurtmalar) {
sanoq.set(taom, (sanoq.get(taom) ?? 0) + 1);
}
const [eng, soni] = [...sanoq].reduce(
(a, b) => (b[1] > a[1] ? b : a),
);
console.log(`${eng} — ${soni} marta`);Konsolda:
osh — 3 marta[...sanoq] — [["osh", 3], ["manti", 2], ["choy", 1]]. reduce boshlang'ich qiymatsiz chaqirildi: akkumulyator — birinchi juftlik. Har qadamda kattarog'i qoladi. Natija juftligini destructuring bilan ochdik.
3-mashq (qiyin): Eng ko'p tushum bergan stol — Map.groupBy bilan
Guruhlash darsidagi masala. Buyurtmalarni stol bo'yicha guruhlang, har stolning jami summasini hisoblang va { stol, summa } massivini summa kamayishi tartibida chiqaring. Bu safar Map.groupBy ishlating — stol raqami son bo'lib qolsin, Number kerak bo'lmasin.
const buyurtmalar = [
{ stol: 3, summa: 75000 },
{ stol: 1, summa: 40000 },
{ stol: 3, summa: 33000 },
{ stol: 7, summa: 120000 },
{ stol: 1, summa: 28000 },
];Yechim
const buyurtmalar = [
{ stol: 3, summa: 75000 },
{ stol: 1, summa: 40000 },
{ stol: 3, summa: 33000 },
{ stol: 7, summa: 120000 },
{ stol: 1, summa: 28000 },
];
const stollar = Map.groupBy(buyurtmalar, (b) => b.stol);
const hisobot = [...stollar]
.map(([stol, royxat]) => ({
stol,
summa: royxat.reduce((jami, b) => jami + b.summa, 0),
}))
.toSorted((a, b) => b.summa - a.summa);
console.log(hisobot);
console.log(stollar.has(3), stollar.has("3"));Konsolda:
[
{ stol: 7, summa: 120000 },
{ stol: 3, summa: 108000 },
{ stol: 1, summa: 68000 }
]
true falseIkki farq bor. Object.entries(stollar) o'rniga [...stollar] — Map dan juftliklar massivi. stol: Number(stol) o'rniga shunchaki stol — kalit son bo'lib qolgan. Oxirgi qator buni isbotlaydi: has(3) — true, has("3") — false.
4-mashq: Vazifalar qadami — teglar hisobi
vazifalar ga yangi imkoniyat qo'shamiz: teglar. Teg — vazifa matnidagi # bilan boshlanadigan so'z: "Sabzi olish #bozor #uy". Matnni maxsus ajratmaymiz — teglar shunchaki matn ichida yoziladi. Bu va keyingi ikki darsda ular bilan ishlaymiz.
Bugungi talab: hisob ostida yangi qator — Teglar: #bozor — 2, #uy — 1. Teg yo'q bo'lsa — qator yashirin.
- Yangi branch:
git switch -c feature/teglar. Bu refaktoring emas — xulq o'zgaradi, shuning uchun prefiksfeature/. - HTML'da
#hisobdan keyin:<p id="teglar" hidden></p>. JS'da "2. Sahifa elementlari" gateglarQatori. - Ikki yangi kod:
teglariniOl(matn)— matndagi teglar massivi. Oddiy toza funksiya,VazifalarRoyxatiklassidan oldin. Ishora:split(" ")vafilter— so'z#bilan boshlansin va undan uzunroq bo'lsin (Kesish, bo'lish va to'ldirish).tegHisobi()—VazifalarRoyxatining yangi metodi:Map, teg → nechta vazifada uchradi. Ishora: avvalflatMapbilan#vazifalardagi hamma teglarni bitta massivga yig'ing, so'ngreduce— akkumulyatornew Map()(setMapni qaytarishini eslang).
- "3. Hisoblovchi funksiyalar" ga
teglarMatni(sanoq)—Mapdan#bozor — 2, #uy — 1satri.render()oxirida qatorni yangilang.
Yechim
HTML:
<p id="hisob" aria-live="polite"></p>
<p id="teglar" hidden></p>"2. Sahifa elementlari":
const teglarQatori = document.getElementById("teglar");VazifalarRoyxati klassidan oldin:
function teglariniOl(matn) {
return matn
.split(" ")
.filter((soz) => soz.length > 1 && soz.startsWith("#"));
}VazifalarRoyxati ichida, matnBormi dan keyin:
tegHisobi() {
return this.#vazifalar
.flatMap((vazifa) => teglariniOl(vazifa.matn))
.reduce(
(sanoq, teg) => sanoq.set(teg, (sanoq.get(teg) ?? 0) + 1),
new Map(),
);
}Nega metod? Teglar — vazifalar to'plami haqidagi savol, #vazifalar esa faqat klass ichida ko'rinadi (OOP tamoyillari va kompozitsiya). holat.vazifalar — massiv emas, VazifalarRoyxati: unda flatMap yo'q, global funksiyadan holat.vazifalar.flatMap(...) deb yozsak — TypeError.
"3. Hisoblovchi funksiyalar":
function teglarMatni(sanoq) {
return [...sanoq]
.map(([teg, soni]) => `${teg} — ${soni}`)
.join(", ");
}render() oxirida, hisob qatoridan ("2 ta vazifa qoldi, 1 ta bajarildi") keyin:
const sanoq = holat.vazifalar.tegHisobi();
teglarQatori.hidden = sanoq.size === 0;
matnniYoz(teglarQatori, `Teglar: ${teglarMatni(sanoq)}`);reduce callback'i sanoq.set(...) ni qaytaradi — set esa Map ning o'zini qaytaradi. Shuning uchun akkumulyator har qadamda o'sha bitta Map bo'lib qoladi (reduce darsida "akkumulyator Map ham bo'lishi mumkin" degan edik). Nom — sanoq, hisob emas: hisob — sahifadagi element, bir xil nom uni soyalab qo'yardi (TDZ darsidagi tuzoq).
Funksiyalarni avval Node'da sinang — brauzersiz, aniq ma'lumot bilan. Klass shart emas: tegHisobi ni oddiy funksiya qilamiz, this.#vazifalar o'rniga — vazifalar parametri. Ichi bir xil:
function teglariniOl(matn) {
return matn
.split(" ")
.filter((soz) => soz.length > 1 && soz.startsWith("#"));
}
function tegHisobi(vazifalar) {
return vazifalar
.flatMap((vazifa) => teglariniOl(vazifa.matn))
.reduce(
(sanoq, teg) => sanoq.set(teg, (sanoq.get(teg) ?? 0) + 1),
new Map(),
);
}
const vazifalar = [
{ matn: "Non olish" },
{ matn: "Sabzi olish #bozor #uy" },
{ matn: "Guruch olish #bozor" },
{ matn: "Kitob # o'qish" },
];
console.log(teglariniOl("Sabzi olish #bozor #uy"));
console.log(tegHisobi(vazifalar));
console.log(tegHisobi([]).size);Konsolda:
[ '#bozor', '#uy' ]
Map(2) { '#bozor' => 2, '#uy' => 1 }
0Yolg'iz # teg hisoblanmadi — soz.length > 1 sharti shuning uchun. Bo'sh ro'yxatda Map bo'sh, size — 0, qator yashirinadi.
Node'da vazifalar — oddiy obyektlar, ilovada esa Vazifa klassining nusxalari (Private maydon va metodlar). Farqi yo'q: teglariniOl faqat vazifa.matn ni o'qiydi, klassda esa u getter orqali o'qiladi. Teglar matnning bir qismi bo'lgani uchun eksport formati ham o'zgarmaydi — { versiya: 1, vazifalar } dagi matn ular bilan birga yoziladi (JSON asoslari).
Brauzerda tekshiring:
- Ochilganda teg yo'q — yangi qator ko'rinmaydi, qolgan hamma narsa avvalgidek.
- "Sabzi olish #bozor #uy" qo'shing —
Teglar: #bozor — 1, #uy — 1. - "Guruch olish #bozor" qo'shing —
#bozor — 2. Uni o'chiring — yana1. - "Sabzi…" ni tahrirlab, teglarni olib tashlang va saqlang — qator yashirinadi.
Commit: Vazifalar: teglar hisobi (Map). Branch'ni hali main ga qo'shmang — keyingi ikki darsda teglar yaxshilanadi.
12. Real ishda
- Kesh. "So'rov → javob", "foydalanuvchi id → profil" jadvallari deyarli doim
Map. Memoization darsida keshniMapbilan qayta yozamiz. - Statistika. Analitika va admin panellarda "sahifa → ko'rishlar soni", "mahsulot → sotuvlar" — bugungi sanash qolipi. Server loglarini tahlil qiluvchi skriptlarda ham shunday.
- DOM bilan.
Mapkaliti DOM elementi bo'lishi mumkin: "tugma → uning sozlamasi". Element o'chganda xotira qanday tozalanishiniWeakMapdarsida ko'ramiz. - Xavfsizlik. Kod ko'rib chiqishda tashqaridan keladigan kalitlar oddiy obyektga yozilsa, tajribali dasturchi
MapyokiObject.create(null)ni so'raydi — prototype pollution himoyasi. - Intervyu. "
Mapva obyektning farqi nima?" — eng ko'p beriladigan savollardan. Javob: kalit turi, tartib,size, prototip yo'qligi, JSON'ga yozilmasligi.
Xulosa
Map— kalit-qiymat to'plami:set,get,has,delete,clear,size.setMapni qaytaradi — zanjir qilish mumkin.- Kalit istalgan tur va satrga aylantirilmaydi:
3va"3"— ikki kalit. Obyektlar havola bo'yicha solishtiriladi,NaNo'ziga teng. - Tartib — qo'shilgan tartib.
for...ofjuftlik beradi,keys/values/entries— iterator,forEachda avval qiymat, keyin kalit. - JSON
Mapni{}qilib yozadi — oldin[...map]yokiObject.fromEntries(map). - Kalitlari tashqaridan keladigan lug'at —
Map: unda meros kalitlar va__proto__tuzog'i yo'q.
Keyingi dars: Set — faqat takrorlanmas qiymatlarni saqlaydigan to'plam: dublikatlarni bir qatorda olib tashlaymiz va "bormi?" savoliga tez javob beramiz.
Manbalar
- MDN: "Map", "Map.groupBy()", "Map.prototype.getOrInsert()" — developer.mozilla.org
- ECMAScript 2025 Language Specification: "Map Objects", "SameValueZero" — tc39.es/ecma262
- web-features 3.40:
map,array-group,getorinsert— github.com/web-platform-dx/web-features
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!