Set
Set nima, nega array.includes() o'rniga Set kerak, V8 ichida hash table, SameValueZero, array'ni noyob qilish patterni va Set vs Array solishtiruvi.
34-dars
Set
1. Set nima — asosiy g'oya
Set — faqat noyob (unique) qiymatlarni saqlaydigan kolleksiya. Mapdan farqi: Map — key-value juftlik, Set — faqat qiymatlarning o'zi (key va value bir xil, aslida "key" tushunchasi yo'q).
const set = new Set();
set.add(1);
set.add(2);
set.add(2); // TAKRORLANGAN — E'TIBORGA OLINMAYDI!
set.add('2'); // BOSHQA qiymat (string, number emas) — qo'shiladi
console.log(set.size); // 3
console.log([...set]); // [1, 2, '2']
2. Nega oddiy array emas, Set kerak — muammoni ko'ramiz
// Array bilan noyoblikni ta'minlash — QIMMAT operatsiya
const arr = [1, 2, 3];
function addUnique(arr, val) {
if (!arr.includes(val)) { // includes — O(n), HAR SAFAR BUTUN ARRAYNI TEKSHIRADI!
arr.push(val);
}
}
arr.includes() — chiziqli qidiruv (O(n)): har bir qo'shishda, butun array bo'ylab yurish kerak. Agar minglab element bo'lsa — bu juda sekin bo'lib qoladi (minglab qo'shish = millionlab taqqoslash).
// Set bilan — TEZ, chunki hash table asosida
const set = new Set([1, 2, 3]);
set.add(4); // O(1) — hash orqali, DARHOL tekshiriladi, qidiruv kerak emas
Set ichkarida — xuddi Map kabi hash table asosida ishlaydi, shuning uchun has(), add() — O(1) (o'rtacha holatda), array'ning includes() kabi O(n) emas.
3. V8 ichida Set qanday saqlanadi
Set ICHKI TUZILISHI:
┌─────────────────────────────────┐
│ HashTable │
│ bucket[hash(1)] → entry: 1 │
│ bucket[hash(2)] → entry: 2 │
│ bucket[hash('2')] → entry: '2' │
├─────────────────────────────────┤
│ Insertion Order Linked List │ ← Map'dagi kabi, TARTIB SAQLANADI
│ 1 → 2 → '2' │
└─────────────────────────────────┘
Bu — Mapning deyarli aynan bir xil ichki mexanizmi, faqat har bir "entry"da faqat bitta qiymat bor (key=value, aslida ikkalasi bir xil narsa). Ba'zi V8 versiyalarida Map va Set uchun deyarli bir xil ichki OrderedHashTable C++ klass orqali implement qilingan.
4. Noyoblik qanday aniqlanadi — SameValueZero algoritmi
const set = new Set();
set.add(NaN);
set.add(NaN);
console.log(set.size); // 1! — NaN faqat BIR MARTA qo'shildi
console.log(NaN === NaN); // false (odatiy === solishtirish)
Nozik nuqta: Set — === (Strict Equality)dan emas, balki SameValueZero algoritmidan foydalanadi. Bu ikkalasi deyarli bir xil, faqat bitta farq: SameValueZero'da NaN === NaN — true hisoblanadi (odatiy ===da esa false). Bu — Map'da ham xuddi shunday ishlaydi.
const set2 = new Set();
set2.add(+0);
set2.add(-0);
console.log(set2.size); // 1 — +0 va -0 BIR XIL hisoblanadi (SameValueZero'da)
5. Obyektlar bilan Set — pointer orqali solishtirish
const set = new Set();
set.add({ id: 1 });
set.add({ id: 1 }); // BOSHQA obyekt (boshqa pointer) — QO'SHILADI!
console.log(set.size); // 2! — mazmuni bir xil bo'lsa ham, IKKI XIL manzil
Set — obyektlarni mazmuni bo'yicha emas, pointer (manzil) bo'yicha solishtiradi — chunki Set ichkarida ham ===/SameValueZero ishlatadi, va biz bilamizki, {} === {} — har doim false.
6. Amaliy holat 1 — Array'ni noyob qilish (eng ko'p ishlatiladigan pattern)
const arr = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(arr)];
console.log(unique); // [1, 2, 3, 4]
Bu — bitta qatorda massivni noyob qilishning eng tez, eng qisqa usuli. Ichkarida: new Set(arr) — array elementlarini hash tablega qo'shadi (takrorlar avtomatik tashlanadi), keyin spread (...) orqali qaytadan array'ga aylantiriladi.
7. Amaliy holat 2 — tez has() tekshiruvi (performance uchun)
// ❌ SEKIN — har safar O(n) qidiruv
const blockedUsers = ['user1', 'user2', 'user3', /* ...minglab element */];
function isBlocked(user) {
return blockedUsers.includes(user); // O(n) — HAR SAFAR!
}
// ✅ TEZ — O(1) qidiruv
const blockedUsersSet = new Set(['user1', 'user2', 'user3', /* ...minglab element */]);
function isBlocked(user) {
return blockedUsersSet.has(user); // O(1) — hash orqali darhol
}
Qoida: agar sizga tez-tez "shu qiymat bormi?" tekshiruvi kerak bo'lsa (masalan "blocklist", "allowlist", "ko'rilgan ID'lar"), array o'rniga har doim Set ishlating.
8. Set metodlari — to'liq
const set = new Set([1, 2, 3]);
set.has(2); // true
set.add(4); // Set { 1, 2, 3, 4 }
set.delete(1); // true — o'chirildi
set.size; // 3
for (const val of set) {
console.log(val); // 2, 3, 4 — qo'shilish tartibida
}
set.forEach(val => console.log(val));
[...set]; // [2, 3, 4] — array'ga aylantirish
set.clear(); // barchasini tozalash
Qiziq nozik nuqta: Set'da keys() va values() — bir xil natija qaytaradi (chunki key va value farqi yo'q), bu — API'ni Map bilan izchil (consistent) qilish uchun ataylab shunday qilingan:
console.log([...set.keys()]); // [2, 3, 4]
console.log([...set.values()]); // [2, 3, 4] — XUDDI SHU
console.log([...set.entries()]); // [[2,2], [3,3], [4,4]] — [value, value] juftligi
9. Set vs Array — to'liq solishtirish jadvali
| Array | Set | |
|---|---|---|
| Takrorlanuvchi qiymat | Ruxsat etiladi | Avtomatik rad etiladi |
includes/has tezligi |
O(n) — chiziqli qidiruv | O(1) — hash orqali (o'rtacha) |
Index orqali kirish (arr[0]) |
✅ Bor | ❌ Yo'q — faqat iteratsiya orqali |
| Tartib | Index bo'yicha, kafolatlangan | Qo'shilish tartibida, kafolatlangan |
| Element turi | Har qanday, PACKED/HOLEY elements kind | Har qanday, lekin hash table asosida |
10. WeakSet bilan chalkashtirmaslik uchun eslatma
Set — obyektlarni kuchli (strong) referens bilan saqlaydi, ya'ni agar siz obyektni Set'ga qo'shsangiz, u boshqa hech qayerda ishlatilmasa ham, garbage collector uni yig'ib olmaydi (chunki Set unga hali ham ishora qilib turibdi):
let obj = { data: 'katta' };
const set = new Set([obj]);
obj = null; // asosiy referensni o'chirdik
// Lekin obyekt HALI HAM XOTIRADA — chunki 'set' unga ishora qilib turibdi!
console.log([...set][0]); // { data: 'katta' } — hali ham mavjud
Bu — memory leak manbai bo'lishi mumkin. Aynan shu muammoni WeakSet hal qiladi.
Xulosa
Set — Mapning ichki bir xil hash table + insertion-order mexanizmiga asoslangan, lekin faqat noyob qiymatlarni saqlaydigan kolleksiya; u SameValueZero algoritmi orqali takrorlarni avtomatik chiqarib tashlaydi, has()/add() operatsiyalari O(1) tezlikda ishlaydi (array'ning includes()dagi O(n)dan farqli), va u ham, Map kabi, obyekt qiymatlarini pointer orqali (mazmun emas) solishtiradi.