Hozirgacha biz quyidagi murakkab ma’lumotlar strukturalarini o’rgandik:
- Objektlar kalitli to’plamlarni saqlash uchun ishlatiladi.
- Massivlar tartibli to’plamlarni saqlash uchun ishlatiladi.
Ammo bu real hayot uchun yetarli emas. Shuning uchun Map va Set ham mavjud.
Map
Map – bu Object kabi kalitli ma’lumotlar to’plamidir. Lekin asosiy farq shundaki, Map har qanday turdagi kalitlarga ruxsat beradi.
Metodlar va xususiyatlar:
new Map()– xaritani yaratadi.map.set(key, value)– kalit bo’yicha qiymatni saqlaydi.map.get(key)– kalit bo’yicha qiymatni qaytaradi, agarkeyxaritada mavjud bo’lmasaundefinedqaytaradi.map.has(key)– agarkeymavjud bo’lsatrue, aks holdafalseqaytaradi.map.delete(key)– kalit bo’yicha qiymatni o’chiradi.map.clear()– xaritadagi hamma narsani o’chiradi.map.size– hozirgi elementlar sonini qaytaradi.
Misol uchun:
let map = new Map();
map.set('1', 'str1'); // satr kaliti
map.set(1, 'num1'); // raqamli kalit
map.set(true, 'bool1'); // mantiqiy kalit
// oddiy Objektni eslaysizmi? u kalitlarni satrga aylantiradi
// Map turni saqlaydi, shuning uchun bu ikkalasi har xil:
alert( map.get(1) ); // 'num1'
alert( map.get('1') ); // 'str1'
alert( map.size ); // 3
Ko’rib turganingizdek, objektlardan farqli o’laroq, kalitlar satrga aylantirilmaydi. Har qanday turdagi kalit mumkin.
map[key] – bu Map dan foydalanishning to’g’ri usuli emasGarchi map[key] ham ishlaydi, masalan, biz map[key] = 2 qo’ya olamiz, lekin bu map ni oddiy JavaScript objekti sifatida ko’rib chiqadi, shuning uchun barcha mos cheklovlar keladi (faqat satr/simvol kalitlar va boshqalar).
Shuning uchun biz map metodlaridan foydalanishimiz kerak: set, get va boshqalar.
Map objektlarni ham kalit sifatida ishlatishi mumkin.
Misol uchun:
let john = { name: "John" };
// har bir foydalanuvchi uchun ularning tashrif sonini saqlaymiz
let visitsCountMap = new Map();
// john - xarita uchun kalit
visitsCountMap.set(john, 123);
alert( visitsCountMap.get(john) ); // 123
Objektlarni kalit sifatida ishlatish Map ning eng muhim va diqqatga sazovor xususiyatlaridan biridir. Bu Object uchun amal qilmaydi. Object da satr kalit yaxshi, lekin biz boshqa Object ni Object da kalit sifatida ishlatib bo’lmaydi.
Sinab ko’raylik:
let john = { name: "John" };
let ben = { name: "Ben" };
let visitsCountObj = {}; // objektdan foydalanishga harakat qilaylik
visitsCountObj[ben] = 234; // ben objektini kalit sifatida ishlatishga harakat qilish
visitsCountObj[john] = 123; // john objektini kalit sifatida ishlatishga harakat qilish, ben objekti almashtiriladi
// Mana nima yozilgan!
alert( visitsCountObj["[object Object]"] ); // 123
visitsCountObj objekt bo’lganligi sababli, u barcha Object kalitlarini, masalan yuqoridagi john va ben ni bir xil "[object Object]" satrga aylantiradi. Bu biz xohlagan narsa emas.
Map kalitlarni qanday solishtiradiKalitlarning ekvivalentligini tekshirish uchun Map SameValueZero algoritmidan foydalanadi. Bu qat’iy tenglik === bilan deyarli bir xil, lekin farqi shundaki, NaN NaN ga teng deb hisoblanadi. Shuning uchun NaN ham kalit sifatida ishlatilishi mumkin.
Ushbu algoritm o’zgartirilishi yoki sozlanishi mumkin emas.
Har bir map.set chaqiruvi xaritaning o’zini qaytaradi, shuning uchun biz chaqiruvlarni “zanjir” qila olamiz:
map.set('1', 'str1')
.set(1, 'num1')
.set(true, 'bool1');
Map ustida iteratsiya
Map ustida sikl uchun 3 ta metod mavjud:
map.keys()– kalitlar uchun iterable qaytaradi,map.values()– qiymatlar uchun iterable qaytaradi,map.entries()–[key, value]yozuvlari uchun iterable qaytaradi, ufor..ofda standart bo’yicha ishlatiladi.
Misol uchun:
let recipeMap = new Map([
['cucumber', 500],
['tomatoes', 350],
['onion', 50]
]);
// kalitlar ustida iteratsiya (sabzavotlar)
for (let vegetable of recipeMap.keys()) {
alert(vegetable); // cucumber, tomatoes, onion
}
// qiymatlar ustida iteratsiya (miqdorlar)
for (let amount of recipeMap.values()) {
alert(amount); // 500, 350, 50
}
// [key, value] yozuvlari ustida iteratsiya
for (let entry of recipeMap) { // recipeMap.entries() bilan bir xil
alert(entry); // cucumber,500 (va hokazo)
}
Iteratsiya qiymatlar kiritilgan tartibda boradi. Map bu tartibni saqlaydi, oddiy Object dan farqli o’laroq.
Bundan tashqari, Map Array ga o’xshash o’rnatilgan forEach metodiga ega:
// har bir (key, value) juftlik uchun funktsiyani ishga tushiradi
recipeMap.forEach( (value, key, map) => {
alert(`${key}: ${value}`); // cucumber: 500 va hokazo
});
Object.entries: Objektdan Map
Map yaratilganda, biz uni boshlash uchun kalit/qiymat juftliklari massivini (yoki boshqa iterable) uzatishimiz mumkin:
// [key, value] juftliklari massivi
let map = new Map([
['1', 'str1'],
[1, 'num1'],
[true, 'bool1']
]);
alert( map.get('1') ); // str1
Agar bizda oddiy objekt bor va undan Map yaratmoqchi bo’lsak, u holda Object.entries(obj) o’rnatilgan metodidan foydalanishimiz mumkin, u objekt uchun aynan shu formatdagi kalit/qiymat juftliklari massivini qaytaradi.
Shunday qilib objektdan xarita yaratishimiz mumkin:
let obj = {
name: "John",
age: 30
};
let map = new Map(Object.entries(obj));
alert( map.get('name') ); // John
Bu erda Object.entries kalit/qiymat juftliklari massivini qaytaradi: [ ["name","John"], ["age", 30] ]. Map ga aynan shu kerak.
Object.fromEntries: Map dan objekt
Biz hozirgina Object.entries(obj) yordamida oddiy objektdan Map yaratishni ko’rdik.
Teskarisini bajaradigan Object.fromEntries metodi mavjud: [key, value] juftliklari massivini hisobga olgan holda, u ulardan objekt yaratadi:
let prices = Object.fromEntries([
['banana', 1],
['orange', 2],
['meat', 4]
]);
// endi prices = { banana: 1, orange: 2, meat: 4 }
alert(prices.orange); // 2
Biz Map dan oddiy objekt olish uchun Object.fromEntries dan foydalanishimiz mumkin.
Masalan, biz ma’lumotlarni Map da saqlaymiz, lekin uni oddiy objekt kutadigan uchinchi tomon kodiga uzatishimiz kerak.