Mundarija (34)
- Bu darsda
- 1. Nega bu kerak?
- 2. Massivga o'xshash obyekt
- 2.1 O'zimiz yasaymiz
- 2.2 Qayerda uchraydi?
- 3. Haqiqiy massivga aylantirish
- 3.1 Array.from
- 3.2 Spread: faqat iterable bo'lsa
- 3.3 Brauzerda: HTMLCollection va NodeList
- 4. Teshikli massivlar
- 4.1 Teshik qanday paydo bo'ladi
- 4.2 Metodlar teshikni har xil ko'radi
- 4.3 Real xato: hafta o'rtachasi
- 5. length — oddiy xususiyat emas
- 5.1 length qanday hisoblanadi
- 5.2 length ga yozish
- 5.3 delete — yana bir bor
- 6. Teshiksiz massiv yasash
- 6.1 new Array(n) tuzog'i
- 6.2 Tezlik haqida bir gap
- 7. Ko'p uchraydigan xatolar
- 7.1 children.forEach is not a function
- 7.2 Qo'lda yasalgan obyektni spread qilish
- 7.3 new Array(n).map(...) bo'sh qoladi
- 7.4 O'rtacha yoki sanoq length ga tayanadi
- 7.5 delete massiv[i]
- 8. Mashqlar
- 1-mashq (oson): arguments dan massiv
- 2-mashq (o'rta): Teshiklarni sanash
- 3-mashq (qiyin): Har qanday "ro'yxat"dan massiv
- 4-mashq: Mashqlar qadami — teshikka chidamli tushum hisoboti
- 9. Real ishda
- Xulosa
- Manbalar
JavaScript massivga o'xshash obyektlar va teshikli massivlar: arguments, NodeList va bo'sh kataklar
Qisqacha: Massivga o'xshash obyekt (array-like) — indeksli elementlari va
lengthi bor, lekinmap,filterkabi metodlari yo'q obyekt:arguments,HTMLCollection,{ 0: "osh", length: 1 }. Uni haqiqiy massivgaArray.from(x)aylantiradi. Teshikli massiv esa — ichida bo'sh katagi bor massiv ([1, , 3]); metodlar teshikni har xil ko'radi, shuning uchun teshik yaratmang.
Bu darsda
- Massivga o'xshash obyektni haqiqiy massivdan ajrata olasiz va
Array.isArraybilan tekshira olasiz. arguments,NodeList,HTMLCollectionniArray.fromyoki spread bilan massivga aylantira olasiz.- Iterable va massivga o'xshash farqini va qachon spread ishlamasligini tushuntira olasiz.
- Teshik qanday paydo bo'lishini va qaysi metod uni qanday ko'rishini bilasiz.
lengthga yozish vadelete arr[i]tuzoqlarini taniysiz.
Oldin bilishingiz kerak: flat, flatMap, fill va Array.from, Metod zanjiri, Element qo'shish va olib tashlash, Parametrlar va arguments, Elementlarni tanlash.
1. Nega bu kerak?
09-qismda bu xatoni ko'rgan edingiz (DOM bo'ylab harakatlanish):
Uncaught TypeError: menyu.children.forEach is not a functionmenyu.children ichida elementlar bor edi. Ularni indeks bilan olish mumkin edi, length ham bor edi. Lekin forEach yo'q chiqdi. O'shanda "for...of ishlating" dedik va o'tib ketdik. Bugun sababini ochamiz.
JavaScript'da "ro'yxatga o'xshab ko'rinadigan" narsalar ko'p. Ularning hammasi ham massiv emas. Bir xili — haqiqiy massiv. Boshqasi esa faqat massivga o'xshaydi: raqamli kataklari va uzunligi bor, xolos.
Hayotdan o'xshatish: «Bahor»dagi qog'oz navbat ro'yxati. Unda raqamlar bor (1, 2, 3...) va oxirida "jami: 5 kishi" deb yozilgan. Lekin bu oddiy qog'oz — elektron navbat tizimidagi "saralash" yoki "qidirish" tugmalari unda yo'q. Tugmalar kerak bo'lsa, ro'yxatni tizimga ko'chirib kiritasiz. Massivga o'xshash obyektni ham avval haqiqiy massivga ko'chirasiz.
Darsning ikkinchi qismi — teshikli massivlar. Massiv yaratish va Element qo'shish darslarida <3 empty items> degan g'alati yozuvni ko'rgan edik va "teshiklar keyin kutilmagan natija beradi" deb va'da qilgan edik. Bugun shu kutilmagan natijalarni o'z ko'zimiz bilan ko'ramiz — va ulardan qanday qochishni o'rganamiz.
2. Massivga o'xshash obyekt
2.1 O'zimiz yasaymiz
Massivga o'xshash obyektni qo'lda yasash mumkin. Kalitlari — 0, 1, 2..., yana bitta length xususiyati:
const navbat = { 0: "Ali", 1: "Malika", 2: "Bobur", length: 3 };
console.log(navbat[1]); // Malika
console.log(navbat.length); // 3
console.log(Array.isArray(navbat)); // falseIndeks bilan o'qish ishladi, uzunlik ham bor. Lekin Array.isArray — "bu haqiqiy massivmi?" degan savolga — false dedi. Obyekt kalitlari doim satr, navbat[1] esa navbat["1"] ning o'zi (Obyekt: kalit-qiymat juftliklari). Ya'ni bu shunchaki kalitlari raqamga o'xshagan oddiy obyekt.
Massivga o'xshash obyekt (array-like object) — ikki shartga javob beradigan har qanday obyekt: unda length bor va elementlari 0, 1, 2... kalitlarida turadi. Massiv metodlari (map, filter, forEach) unda yo'q.
Metod chaqirsangiz:
const navbat = { 0: "Ali", 1: "Malika", length: 2 };
navbat.map((ism) => ism.toUpperCase());TypeError: navbat.map is not a functionTarjimasi: "navbat.map — funksiya emas". navbat da map degan xususiyat umuman yo'q — undefined. undefined ni chaqirib bo'lmaydi. Xato map qatorida chiqqani to'g'ri: muammo obyektda emas, unda kutgan metodingiz yo'qligida.
2.2 Qayerda uchraydi?
Massivga o'xshash obyektni qo'lda kam yasaysiz. Lekin tayyorlari bilan har kuni uchrashasiz:
| Nima | Qayerdan keladi | forEach bormi? |
|---|---|---|
arguments |
oddiy function ichida (Parametrlar) |
yo'q |
HTMLCollection |
children, getElementsByClassName |
yo'q |
NodeList |
querySelectorAll, childNodes |
bor |
| Satr | "salom" |
yo'q (lekin [0] va length bor) |
| Typed array | Typed arrays darsida | bor |
NodeList — o'rtadagi holat: brauzer unga forEach ni qo'shib bergan, lekin map, filter, reduce yo'q. Shuning uchun Callback imzosi darsida vazifalar dagi filtr tugmalarini forEach bilan aylantira oldik, map bilan esa aylantira olmasdik.
arguments ni Parametrlar darsida "ro'yxatga o'xshaydi, lekin to'liq ro'yxat emas" degan edik. Mana isboti:
function narxlarniKor() {
console.log(arguments);
console.log(Array.isArray(arguments));
console.log(typeof arguments.map);
}
narxlarniKor(35000, 28000);Konsolda:
[Arguments] { '0': 35000, '1': 28000 }
false
undefinedNode arguments ni [Arguments] { '0': ..., '1': ... } deb ko'rsatdi — massiv qavsi [ ] emas, obyekt qavsi { }. Kalitlar qo'shtirnoqda, ya'ni satr. Ichki tuzilish konsolning o'zida ko'rinib turibdi.
Tekshirib ko'ring:
const x = { 0: "osh", length: 1 };—x.lengthvaArray.isArray(x)nima qaytaradi?x.push("manti")chi?
Javob
1 va false. x.push(...) esa TypeError: x.push is not a function beradi — push ham massiv metodi, oddiy obyektda u yo'q. length — x ning oddiy xususiyati, uni biz o'zimiz yozdik.
3. Haqiqiy massivga aylantirish
3.1 Array.from
flat, fill va Array.from darsida Array.from ni ko'rgan edik: "shundan massiv yasa". U massivga o'xshash obyektni ham qabul qiladi:
const navbat = { 0: "Ali", 1: "Malika", 2: "Bobur", length: 3 };
const massiv = Array.from(navbat);
console.log(massiv); // [ 'Ali', 'Malika', 'Bobur' ]
console.log(Array.isArray(massiv)); // true
console.log(massiv.map((ism) => ism.length)); // [ 3, 6, 5 ]Array.from length ni o'qiydi va 0 dan length - 1 gacha har kalitni oladi. Natija — yangi, haqiqiy massiv. Endi unda map ham, filter ham bor.
Ikkinchi argument — har elementni aylantiradigan callback. U map ni alohida chaqirishdan qutqaradi:
function jamiHisobla() {
const narxlar = Array.from(arguments, (x) => Number(x));
return narxlar.reduce((jami, n) => jami + n, 0);
}
console.log(jamiHisobla("35000", "28000", 5000)); // 68000arguments dagi satrlar songa aylandi, keyin reduce ularni yig'di.
3.2 Spread: faqat iterable bo'lsa
[...x] ham massiv yasaydi. Lekin u boshqa qoidaga tayanadi. for...of darsida iterable atamasini ko'rgan edik — "ichidagi qiymatlarni birma-bir bera oladigan narsa". Spread faqat iterable bilan ishlaydi:
const navbat = { 0: "Ali", 1: "Malika", length: 2 };
console.log([...navbat]);TypeError: navbat is not iterableTarjimasi: "navbat — iterable emas". Qo'lda yasalgan massivga o'xshash obyektda length bor, lekin "birma-bir berish" qobiliyati yo'q. Array.from esa ikkalasini ham tushunadi: avval iterable'mi deb tekshiradi, bo'lmasa length va indekslarga qaraydi.
Tayyor brauzer to'plamlari va arguments — ikkalasi ham: massivga o'xshash va iterable. Shuning uchun ular bilan spread ham ishlaydi:
function ismlar() {
return [...arguments];
}
console.log(ismlar("Ali", "Malika")); // [ 'Ali', 'Malika' ]Ikki tushunchani jadvalda solishtiring:
| Massivga o'xshash | Iterable | |
|---|---|---|
| Nima kerak | length + 0, 1, 2... kalitlar |
birma-bir berish qobiliyati |
Array.from(x) |
ishlaydi | ishlaydi |
[...x], for...of |
ishlamaydi | ishlaydi |
| Misol | { 0: "a", length: 1 } |
arguments, NodeList, satr |
"Birma-bir berish" qobiliyati ichida qanday ishlashini Iteratsiya protokoli darsida ochamiz — hozir bilish shart emas.
Qaysi usulni tanlash kerakligini sxemada kuzating — har savolda chap tomon "ha", o'ng tomon "yo'q":
flowchart TD
A{"Array.isArray(x)?"} -- "ha" --> M["Massiv: metodlar tayyor"]
A -- "yo'q" --> I{"for...of bilan aylanadimi?"}
I -- "ha, iterable" --> S["[...x] yoki Array.from(x)"]
I -- "yo'q" --> L{"length bormi?"}
L -- "ha" --> F["Faqat Array.from(x)"]
L -- "yo'q" --> O["Massiv emas: Object.values(x)"]Oxirgi tarmoq — oddiy obyekt, masalan { osh: 35000 }. Uning qiymatlari kerak bo'lsa — Obyekt bo'ylab yurish darsidagi Object.values.
Maslahat: Eski kodlarda
Array.prototype.slice.call(arguments)degan yozuvni uchratasiz. Bu —Array.frompaydo bo'lishidan (2015) oldingi usul: massivningslicemetodini massivga o'xshash obyektga "qarzga berish".callnicall,apply,binddarsida o'rganamiz. Yangi kodda —Array.fromyoki[...x].
3.3 Brauzerda: HTMLCollection va NodeList
Endi 09-qismdagi xatoni tuzatamiz. Natijani oching va konsol paneliga qarang — ikkala to'plamda nima bor, nima yo'q:
<ul id="menyu">
<li>Osh</li>
<li>Lag'mon</li>
<li>Manti</li>
</ul>
<script>
const menyu = document.getElementById("menyu");
const bolalar = menyu.children;
const topilgan = menyu.querySelectorAll("li");
console.log(Array.isArray(bolalar), Array.isArray(topilgan));
console.log(typeof bolalar.forEach, typeof topilgan.forEach);
console.log(typeof topilgan.map);
const nomlar = Array.from(bolalar, (li) => li.textContent);
console.log(nomlar);
const uzunlar = [...topilgan].filter(
(li) => li.textContent.length > 4,
);
console.log(uzunlar);
</script>Konsolda:
false false
undefined function
undefined
(3) ['Osh', "Lag'mon", 'Manti']
(2) [li, li]Ikkala to'plam ham massiv emas. HTMLCollection da forEach yo'q, NodeList da bor, map esa ikkalasida ham yo'q. Array.from va spread esa ikkalasini ham haqiqiy massivga aylantirdi — endi filter va map ishlaydi.
Brauzer konsoli massivni (3) ['Osh', ...] deb ko'rsatadi: oldida uzunlik qavsda. Node'da xuddi shu massiv [ 'Osh', "Lag'mon", 'Manti' ] ko'rinadi — ma'nosi bir xil.
Diqqat:
HTMLCollectionjonli — DOM o'zgarsa, u ham o'zgaradi (Elementlarni tanlash).Array.from(menyu.children)esa o'sha lahzadagi suratni oladi: keyin qo'shilganlimassivga tushmaydi. Elementlarni aylanib o'chirish kerak bo'lsa, bu aynan foydali — massiv sikl davomida qisqarmaydi.
Tekshirib ko'ring:
document.querySelectorAll("li").map(...)nima beradi? Uni qanday tuzatasiz?
Javob
TypeError: document.querySelectorAll(...).map is not a function. NodeList da forEach bor, map esa yo'q. Tuzatish: Array.from(document.querySelectorAll("li"), (li) => ...) yoki [...document.querySelectorAll("li")].map(...).
4. Teshikli massivlar
4.1 Teshik qanday paydo bo'ladi
Teshik (hole) — massivda indeksi bor, lekin unga hech qachon qiymat yozilmagan katak. Teshikli massiv (sparse array) — shunday katagi bor massiv. Teshik undefined qiymatli katakdan farq qiladi: unda qiymat umuman yo'q.
Teshik besh xil yo'l bilan paydo bo'ladi:
const a = [1, , 3]; // ikki vergul orasi bo'sh
const b = ["non"];
b[3] = "sut"; // uzoq indeksga yozish
const c = [1, 2, 3];
delete c[1]; // delete operatori
const d = new Array(3); // uzunlik bilan yaratish
const e = ["osh"];
e.length = 3; // length ni oshirish
console.log(a); // [ 1, <1 empty item>, 3 ]
console.log(b); // [ 'non', <2 empty items>, 'sut' ]
console.log(c); // [ 1, <1 empty item>, 3 ]
console.log(d); // [ <3 empty items> ]
console.log(e); // [ 'osh', <2 empty items> ]Node teshikni <1 empty item> — "1 ta bo'sh element" deb ko'rsatadi. Chrome konsoli [1, empty, 3] deydi — ma'nosi bir xil.
Teshikni undefined dan ajratishning aniq yo'li — in operatori. U "shu kalit obyektda bormi?" deb so'raydi:
const teshikli = [1, , 3];
const undefinedli = [1, undefined, 3];
console.log(teshikli[1], undefinedli[1]); // undefined undefined
console.log(1 in teshikli); // false
console.log(1 in undefinedli); // trueIkkalasida ham [1] o'qilganda undefined chiqdi. Lekin in farqni ko'rsatdi: birinchisida 1 kaliti umuman yo'q. Massiv ham obyekt — teshik esa kaliti yo'q indeks.
Hayotdan o'xshatish: kinoteatr qatori. undefined — o'rindiq bor, lekin hozir bo'sh. Teshik — o'rindiqning o'zi olib tashlangan, raqami esa qatorda qolgan. Ikkalasida ham "hech kim o'tirmagan". Lekin farrosh bo'sh o'rindiqni artadi, o'rindiq yo'q joyni esa o'tib ketadi.
4.2 Metodlar teshikni har xil ko'radi
Teshikning asosiy xavfi shu. Bir xil massiv, uch xil yo'l:
const r = [10, , 30];
r.forEach((x, i) => console.log("forEach", i, x));
for (const x of r) {
console.log("for...of", x);
}
console.log(r.map((x) => x * 2));Konsolda:
forEach 0 10
forEach 2 30
for...of 10
for...of undefined
for...of 30
[ 20, <1 empty item>, 60 ]forEach teshikni o'tkazib yubordi — callback faqat ikki marta chaqirildi. for...of esa teshikni undefined deb berdi. map callback'ni teshikda chaqirmadi va natijada ham teshik qoldirdi.
Qoida ikkita guruhga bo'linadi:
| Teshikni o'tkazib yuboradi | Teshikni undefined deb ko'radi |
|---|---|
forEach, map, filter |
for...of, spread [...r] |
reduce, some, every |
Array.from, find, findIndex |
Object.keys, for...in |
includes, at, entries |
sort (teshiklarni oxiriga suradi) |
toSorted, toReversed, with |
Jadvalni yodlash shart emas. Asosiy xulosa: bir xil teshikli massiv bilan ikki xil kod ikki xil javob beradi. Eski (ES5, 2009) metodlar teshikni o'tkazib yuboradi. Yangiroqlarining ko'pi (ES2015 dan keyingilari) uni undefined deb ko'radi. indexOf esa o'tkazib yuboradi, includes — yo'q: [1, , 3].indexOf(undefined) — -1, [1, , 3].includes(undefined) — true.
Bitta foydali tomoni bor: teshikli massivni filter dan o'tkazsangiz, teshiklar yo'qoladi. toSorted, with kabi nusxa bilan o'zgartiradigan metodlar esa teshikni undefined ga aylantiradi — natijada teshik qolmaydi.
4.3 Real xato: hafta o'rtachasi
Jasur aka haftalik tushumni yozib boradi. Payshanba kuni Otabek kassaga yozishni unutdi — u yerda teshik qoldi:
const tushum = [];
tushum[0] = 1200000;
tushum[1] = 1500000;
tushum[3] = 1800000; // 2-indeks — payshanba — yozilmadi
const jami = tushum.reduce((s, x) => s + x, 0);
console.log(jami); // 4500000
console.log(jami / tushum.length); // 1125000
let siklJami = 0;
for (const x of tushum) {
siklJami += x;
}
console.log(siklJami); // NaNBitta massiv, ikki natija — va ikkalasi ham noto'g'ri:
reduceteshikni o'tkazib yubordi va yig'indi 4 500 000 chiqdi. Lekinlength— 4: teshik ham sanaldi. O'rtacha 1 125 000 — haqiqiydan past. Uch kun ishlab, to'rtga bo'lindi.for...ofteshikniundefineddeb berdi.1200000 + 1500000 + undefined—NaN(Number turi). Bu yaxshiroq: hech bo'lmasa xato ko'rinib turibdi.
Eng xavflisi — birinchi holat. Raqam ishonarli ko'rinadi, xato xabari yo'q. reduce qaysi kunlarni ko'rganini qadamma-qadam kuzating:
Tuzatish — teshikni ma'noli qiymatga aylantirish va bu haqda ochiq qaror qabul qilish. "Yozilmagan kun" — 0 mi yoki hisobga olinmaydimi? Bu dasturchi emas, Jasur aka hal qiladigan savol. Ikkala variant:
const tushum = [];
tushum[0] = 1200000;
tushum[1] = 1500000;
tushum[3] = 1800000;
// 1-variant: yozilmagan kun — 0 so'm
const nollar = Array.from(tushum, (x) => x ?? 0);
console.log(nollar); // [ 1200000, 1500000, 0, 1800000 ]
// 2-variant: yozilmagan kun hisobga olinmaydi
const yozilgan = tushum.filter(() => true);
const jami = yozilgan.reduce((s, x) => s + x, 0);
console.log(jami / yozilgan.length); // 1500000Array.from teshikni undefined deb beradi, ?? 0 esa uni 0 qiladi (?? operatori). filter(() => true) hamma elementni oladi, lekin teshik callback'ga umuman kelmaydi — shuning uchun yangi massivda u yo'q.
Tekshirib ko'ring:
[5, , 5].reduce((s, x) => s + 1, 0)nima qaytaradi? Nega 3 emas?
Javob
2. reduce teshikda callback'ni chaqirmaydi. Callback faqat ikki marta ishladi — ikki haqiqiy element uchun. Massiv uzunligi 3 bo'lsa ham, "elementlar soni" 2. Teshikli massivda length elementlar sonini aytmaydi.
5. length — oddiy xususiyat emas
5.1 length qanday hisoblanadi
Massivning length i — "elementlar soni" emas, aniqrog'i "eng katta indeks + 1". Teshiksiz massivda bu ikkisi bir xil. Teshikli massivda — farqli:
const b = ["non"];
b[99] = "sut";
console.log(b.length); // 100
console.log(Object.keys(b).length); // 2Ikki element, lekin length — 100. Object.keys haqiqiy kalitlarni sanadi.
5.2 length ga yozish
length ni o'qibgina qolmay, unga yozish ham mumkin. Kamaytirsangiz — massiv qisqaradi, ortiqcha elementlar o'chadi. Oshirsangiz — oxirida teshiklar paydo bo'ladi:
const taomlar = ["osh", "lag'mon", "manti", "ko'k choy"];
taomlar.length = 2;
console.log(taomlar); // [ 'osh', "lag'mon" ]
taomlar.length = 4;
console.log(taomlar); // [ 'osh', "lag'mon", <2 empty items> ]Uzunlik qaytdi, lekin "manti" va "ko'k choy" qaytmadi — ular o'chib ketgan. O'rnida faqat teshiklar.
massiv.length = 0 — massivni tozalashning tanish usuli. U shu massivning o'zini bo'shatadi. Unga boshqa o'zgaruvchi ham qarasa, u ham bo'sh massivni ko'radi (Havola semantikasi). Ba'zan aynan shu kerak, ba'zan — bu xato. massiv = [] esa faqat bitta o'zgaruvchiga yangi massiv beradi (u let bo'lishi kerak), boshqalari eskisini ko'raveradi.
5.3 delete — yana bir bor
Element qo'shish va olib tashlash darsida delete savat[1] tuzog'ini ko'rgan edik. Endi u nega xavfli ekani aniq: delete teshik yaratadi, length esa o'zgarmaydi.
const savat = ["non", "sut", "tuxum"];
delete savat[1];
console.log(savat.length); // 3
const katta = savat.map((m) => m.toUpperCase());
console.log(katta); // [ 'NON', <1 empty item>, 'TUXUM' ]
console.log(savat.join(", ")); // non, , tuxumChekda "non, , tuxum" — ikki vergul orasida bo'sh joy. Xato yo'q, lekin mijoz g'alati chek oladi. To'g'risi — splice(1, 1) (asl massivni o'zgartiradi) yoki toSpliced(1, 1) va filter (yangi massiv qaytaradi, Nusxa bilan o'zgartirish).
6. Teshiksiz massiv yasash
6.1 new Array(n) tuzog'i
1 dan 5 gacha raqamlar kerak. Mantiqan to'g'ri ko'rinadigan kod:
const raqamlar = new Array(5).map((_, i) => i + 1);
console.log(raqamlar); // [ <5 empty items> ]Hech narsa o'zgarmadi! new Array(5) — beshta teshik. map esa teshikda callback chaqirmaydi va teshikni o'z o'rnida qoldiradi. Natija — yana beshta teshik.
Teshiksiz variantlar (Array.from darsidan):
console.log(Array.from({ length: 5 }, (_, i) => i + 1));
console.log(new Array(5).fill(0));
console.log([...new Array(3)]);Konsolda:
[ 1, 2, 3, 4, 5 ]
[ 0, 0, 0, 0, 0 ]
[ undefined, undefined, undefined ]Array.from({ length: 5 }, ...) — massivga o'xshash obyektdan massiv. { length: 5 } da kalitlar yo'q, lekin Array.from har indeksni o'qiydi va undefined oladi — callback esa har birida ishlaydi. fill har katakka qiymat yozadi — teshiklar yo'qoladi. Spread teshikni undefined qiladi.
Maslahat:
new Array(3)vaArray.of(3)ni adashtirmang. Bitta son berilsa,new Array(3)uni uzunlik deb oladi va uchta teshik yasaydi.Array.of(3)esa[3]— bitta elementli massiv. Odatda ikkalasi ham kerak emas:[3]yokiArray.from({ length: 3 })yozing.
6.2 Tezlik haqida bir gap
JavaScript dvigateli V8 (Chrome va Node ichidagi) massivlarni ichki "turlarga" ajratadi. Massivda bir marta teshik paydo bo'lsa, V8 uni "teshikli" turga o'tkazadi. Har o'qishda u endi qo'shimcha tekshiradi: "bu katakda qiymat bormi?". Teshik keyin to'ldirilsa ham, massiv eski, tezroq turiga qaytmaydi (manba: v8.dev, "Elements kinds in V8").
Oddiy dasturda bu farqni sezmaysiz. Lekin o'n minglab elementli hisob-kitoblarda sezilishi mumkin. Chuqurroq — Hidden classes va inline caching darsida. Xulosa o'sha: massivni teshiksiz yarating — push, Array.from, fill bilan.
Tekshirib ko'ring:
Array.from({ length: 3 })vanew Array(3)— qaysi birida teshik bor?[...]bilan tekshirmasdan,inbilan qanday bilasiz?
Javob
new Array(3) da — uchta teshik. Array.from({ length: 3 }) esa [ undefined, undefined, undefined ] — qiymatlari bor kataklar. Tekshirish: 0 in new Array(3) — false, 0 in Array.from({ length: 3 }) — true.
7. Ko'p uchraydigan xatolar
7.1 children.forEach is not a function
HTMLCollection da forEach yo'q. Tuzatish: for...of, yoki Array.from(el.children).forEach(...). querySelectorAll dan kelgan NodeList da esa forEach bor, lekin map/filter yo'q — u holda ham Array.from.
7.2 Qo'lda yasalgan obyektni spread qilish
[...{ 0: "a", length: 1 }] — TypeError: ... is not iterable. Spread iterable talab qiladi. Tuzatish: Array.from(x).
7.3 new Array(n).map(...) bo'sh qoladi
Callback bir marta ham chaqirilmaydi, natija — yana teshiklar. Tuzatish: Array.from({ length: n }, (_, i) => ...).
7.4 O'rtacha yoki sanoq length ga tayanadi
Teshikli massivda length elementlar soni emas. reduce teshikni o'tkazadi, length esa sanaydi — natija jimgina buziladi. Tuzatish: teshikni oldindan aniq qiymatga aylantiring (Array.from(r, (x) => x ?? 0)) yoki filter bilan olib tashlang.
7.5 delete massiv[i]
Teshik yaratadi, length o'zgarmaydi, join da bo'sh joy qoladi. Tuzatish: splice, toSpliced yoki filter.
8. Mashqlar
1-mashq (oson): arguments dan massiv
engArzoni funksiyasi eski uslubda yozilgan — parametrlar o'rniga arguments ishlatadi. Uni o'zgartirmasdan, ichida arguments ni massivga aylantirib, eng kichik narxni toping. Ishora: massivga aylantirgach, reduce yoki Math.min(...massiv) (Math obyekti).
function engArzoni() {
// shu yerga yozing
}
console.log(engArzoni(35000, 28000, 30000, 5000));Yechim
function engArzoni() {
const narxlar = Array.from(arguments);
return Math.min(...narxlar);
}
console.log(engArzoni(35000, 28000, 30000, 5000)); // 5000Math.min(...arguments) ham ishlaydi — arguments iterable. Lekin Array.from niyatni aniq aytadi: "endi massiv bilan ishlayman". Yangi kodda esa arguments o'rniga rest parametr yozing: function engArzoni(...narxlar) — u boshidan haqiqiy massiv (Spread va rest).
2-mashq (o'rta): Teshiklarni sanash
teshiklarSoni(massiv) funksiyasini yozing: massivdagi teshiklar sonini qaytarsin. undefined qiymatli katak teshik emas. Ishora: in operatori yoki Object.keys(massiv).length — haqiqiy kalitlar soni.
console.log(teshiklarSoni([1, , 3, , 5])); // 2
console.log(teshiklarSoni([1, undefined, 3])); // 0
console.log(teshiklarSoni(new Array(4))); // 4Yechim
function teshiklarSoni(massiv) {
return massiv.length - Object.keys(massiv).length;
}
console.log(teshiklarSoni([1, , 3, , 5])); // 2
console.log(teshiklarSoni([1, undefined, 3])); // 0
console.log(teshiklarSoni(new Array(4))); // 4length — teshiklar bilan birga sanaladi. Object.keys — faqat haqiqiy kalitlar. Farqi — teshiklar soni. in bilan ham yozsa bo'ladi: 0 dan length - 1 gacha sikl, har i in massiv false bo'lsa — sanoqni oshiring. Lekin reduce yoki filter bilan sanab bo'lmaydi — ular teshikni ko'rmaydi!
3-mashq (qiyin): Har qanday "ro'yxat"dan massiv
royxatgaAylantir(x) funksiyasini yozing. U uch holatni to'g'ri hal qilsin:
x— massiv: uning nusxasini qaytarsin, teshiklarninullga almashtirib;x— massivga o'xshash yoki iterable (arguments,{ 0: "a", length: 1 }, satr): massivga aylantirsin;- boshqa holat (son,
null, oddiy obyektlengthsiz): bo'sh massiv qaytarsin.
Ishora: Array.from iterable'ni ham, length li obyektni ham tushunadi. Son va null uchun avval typeof va null tekshiruvi (typeof).
Yechim
function royxatgaAylantir(x) {
if (Array.isArray(x)) {
return Array.from(x, (el) => el ?? null);
}
if (x === null || x === undefined) {
return [];
}
if (typeof x === "string" || typeof x.length === "number") {
return Array.from(x);
}
return [];
}
function argumentlar() {
return arguments;
}
console.log(royxatgaAylantir([1, , 3]));
console.log(royxatgaAylantir({ 0: "osh", 1: "manti", length: 2 }));
console.log(royxatgaAylantir(argumentlar("Ali", "Bobur")));
console.log(royxatgaAylantir("non"));
console.log(royxatgaAylantir(42));
console.log(royxatgaAylantir({ osh: 35000 }));Konsolda:
[ 1, null, 3 ]
[ 'osh', 'manti' ]
[ 'Ali', 'Bobur' ]
[ 'n', 'o', 'n' ]
[]
[]Ikki nozik joy. Birinchi if dagi Array.from(x, ...) — massivni ham nusxalaydi: callback teshikda undefined oladi va ?? null uni null qiladi. x.map(...) bunday qila olmasdi — teshikni o'tkazib yuborardi. Ikkinchisi: null tekshiruvi x.length dan oldin turishi shart, aks holda null.length — TypeError. Uchinchi if da satrni alohida tekshirdik: satrda length bor, lekin typeof uni "string" deydi.
4-mashq: Mashqlar qadami — teshikka chidamli tushum hisoboti
Bu dars mavzusi vazifalar ilovasiga tegmaydi — qadam mashqlar reposida (Yaxshi commit darsida ochilgan). 10-qism mashqlari — 10/ papkasida, har dars o'z papkasida.
kurs/mashqlar/10/10-teshikli-massivlar/tushum.js faylini yarating. Unda hisobot(tushum) funksiyasi bo'lsin. U kunlik tushum massivini oladi (ichida teshik bo'lishi mumkin) va obyekt qaytaradi:
kunlar— haftaning nechta kuni (massiv uzunligi);yozilgan— nechta kun haqiqatan yozilgan;yozilmagan— yozilmagan kunlar raqamlari (1 dan boshlab);ortacha— faqat yozilgan kunlar bo'yicha o'rtacha.
Sinov uchun «Real xato: hafta o'rtachasi» bo'limidagi tushum massivini ishlating.
Yechim
function hisobot(tushum) {
const kunlar = Array.from(tushum, (summa, i) => ({
kun: i + 1,
summa,
}));
const yozilgan = kunlar.filter((k) => k.summa !== undefined);
const jami = yozilgan.reduce((s, k) => s + k.summa, 0);
return {
kunlar: tushum.length,
yozilgan: yozilgan.length,
yozilmagan: kunlar
.filter((k) => k.summa === undefined)
.map((k) => k.kun),
ortacha: yozilgan.length === 0 ? 0 : jami / yozilgan.length,
};
}
const tushum = [];
tushum[0] = 1200000;
tushum[1] = 1500000;
tushum[3] = 1800000;
console.log(hisobot(tushum));
console.log(hisobot([]));Konsolda:
{ kunlar: 4, yozilgan: 3, yozilmagan: [ 3 ], ortacha: 1500000 }
{ kunlar: 0, yozilgan: 0, yozilmagan: [], ortacha: 0 }Birinchi qatordagi Array.from — kalit qaror. U teshikni o'tkazmaydi, undefined deb beradi. Shuning uchun har kun obyektga aylanadi va yozilmagan kunni keyin filter aniq topadi. Agar boshida tushum.map(...) yozilsa, teshik obyektga aylanmasdi va "3-kun yozilmagan" degan ma'lumot yo'qolardi. Bo'sh massivda 0 / 0 — NaN bo'lmasligi uchun alohida tekshiruv bor.
Ishga tushiring va commit qiling:
cd ~/kurs/mashqlar
node 10/10-teshikli-massivlar/tushum.js
git add 10/10-teshikli-massivlar
git commit -m "10/10: teshikka chidamli tushum hisobotini qo'sh"9. Real ishda
- DOM bilan ishlash.
Array.from(document.querySelectorAll(...))— brauzer kodidagi eng ko'p uchraydigan qatorlardan biri. Elementlarni saralash, filtrlash yoki ma'lumotga aylantirish kerak bo'lsa — avval massivga aylantiriladi. - Eski kutubxonalar. jQuery kabi eski kutubxonalar o'z to'plamlarini massivga o'xshash obyekt sifatida qaytarardi (
$("li")[0],.length). Eski loyihada ishlasangiz,Array.prototype.slice.call(...)vaargumentsni albatta uchratasiz. - Ma'lumot tozalash. Jadval (Excel, CSV) dan kelgan ma'lumotda bo'sh kataklar ko'p. Ular JS'ga teshik yoki
undefinedbo'lib tushadi. Hisobotdan oldin ularni aniq qiymatga aylantirish — tahlilchining birinchi ishi. - Intervyu. "
[1, , 3].map(x => x * 2)nima qaytaradi?", "argumentsmassivmi?", "NodeListva massiv farqi?" — junior va middle intervyularida uchraydi. Javoblar:[ 2, <1 empty item>, 6 ]; yo'q — massivga o'xshash;NodeListdamap/filteryo'q.
Xulosa
- Massivga o'xshash obyekt —
lengthva raqamli kalitlar bor, metodlar yo'q:arguments,HTMLCollection,NodeList(unda faqatforEachbor). Array.isArray(x)— haqiqiy massivni aniqlashning ishonchli yo'li.Array.from(x)massivga o'xshashni ham, iterable'ni ham massivga aylantiradi;[...x]— faqat iterable'ni.- Teshik — qiymati umuman yo'q katak;
inuniundefineddan ajratadi. - Eski metodlar (
forEach,map,filter,reduce) teshikni o'tkazib yuboradi, yangilari (for...of,Array.from,includes) —undefineddeb ko'radi. - Teshik yaratmang:
delete arr[i],new Array(n), uzoq indeksga yozish o'rniga —splice,Array.from({ length: n }),fill.
Keyingi dars: Typed arrays va binar ma'lumot — fayl, rasm va tarmoq baytlari bilan ishlash uchun ArrayBuffer va Uint8Array kabi maxsus massivlarni o'rganamiz.
Manbalar
- MDN: "Indexed collections" — "Array-like objects" va "Sparse arrays" bo'limlari; "Array.from()" — developer.mozilla.org
- V8 blog: "Elements kinds in V8" — v8.dev/blog/elements-kinds
- ECMAScript 2025 Language Specification: "Array.from", "CreateListFromArrayLike" — tc39.es/ecma262
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!