IlmHamroh
JavaScript Full-stack/10-qism. JavaScript chuqur11/65-dars20 daqiqa
Mundarija (38)

JavaScript typed arrays: ArrayBuffer, Uint8Array va binar ma'lumot bilan ishlash

Qisqacha: Typed array — bir xil turdagi sonlarni qat'iy o'lchamdagi xotirada saqlaydigan maxsus massiv: new Uint8Array(4) — to'rtta baytli katak, har birida 0–255. Xotiraning o'zi — ArrayBuffer, typed array va DataView esa unga turli "ko'zoynak" bilan qaraydi. Fayl, rasm, tarmoq paketi, shifrlash — hammasi baytlar, va JavaScript ular bilan aynan shu vositalar orqali ishlaydi.

Bu darsda

  • Bayt nima ekanini va nega oddiy massiv baytlar uchun noqulayligini tushuntira olasiz.
  • Uint8Array, Int32Array, Float64Array, Float16Array ni yarata olasiz va ularning chegaralarini (toshish, yaxlitlash) bilasiz.
  • ArrayBuffer va bir xotiraga qaraydigan bir nechta ko'rinishni (view) tushuntira olasiz.
  • DataView bilan sonni kerakli bayt tartibida (endianness) yoza va o'qiy olasiz.
  • Matnni baytlarga (TextEncoder) va baytlarni hex/Base64 ko'rinishiga aylantira olasiz.

Oldin bilishingiz kerak: Massivga o'xshash obyektlar va teshikli massivlar, Bitwise operatorlar, Son yozish shakllari va sanoq tizimlari, Unicode va emoji.

1. Nega bu kerak?

Kompyuterdagi har qanday fayl — rasm, PDF, musiqa — oxir-oqibat sonlar ketma-ketligi. Har bir son 0 dan 255 gacha. Masalan, har bir PNG rasm aynan shu sakkiz son bilan boshlanadi:

text
137 80 78 71 13 10 26 10

Bu — PNG faylining "imzosi". Dastur faylni ochganda avval shu sonlarga qaraydi va "bu PNG" deb biladi. Fayl nomidagi .png ga emas — ichidagi baytlarga.

Bunday sonlarni oddiy massivda saqlash mumkinmi? Ha, lekin noqulay. Oddiy massivning har katagiga istalgan narsa sig'adi: 255, -7.5, "salom", obyekt. JavaScript har katak uchun "bu yerda nima turibdi?" degan ma'lumotni ham saqlaydi. Bayt uchun esa bu ortiqcha: unda faqat 0–255 oralig'idagi butun son bo'ladi.

Hayotdan o'xshatish: bozordagi tuxum kassetasi. Unda 30 ta katak, har birining o'lchami bir xil, har biriga aynan bitta tuxum sig'adi. Tarvuz qo'yib bo'lmaydi, 31-tuxum uchun joy yo'q. Lekin aynan shu qat'iylik uni ixcham va tez qiladi: necha tuxum borligini sanash shart emas, istalgan katakni darhol topasiz. Oddiy massiv esa qop — hamma narsa sig'adi, lekin har safar ichini titkilash kerak.

Typed array — aynan shunday kasseta. Har katak bir xil turda va bir xil o'lchamda, uzunligi esa yaratilganda qotadi.

Bu dars vazifalar ga tegmaydi: u yerda baytlar bilan ish yo'q. Lekin keyingi qismlarda — fayl yuklash (File va Blob), tarmoq, shifrlash — typed array'larsiz ish bitmaydi. Bugun poydevorni qo'yamiz.

2. Bayt va Uint8Array

2.1 Bayt nima?

Bayt (byte) — kompyuter xotirasining eng kichik "katagi". Bitta bayt — sakkiz bit, ya'ni sakkizta 0 yoki 1. Bitwise operatorlar darsida bitlar bilan ishlagan edik. Sakkiz bit bilan 2⁸ = 256 xil son yozish mumkin: 0 dan 255 gacha.

Baytlar ko'pincha o'n oltilik (hex) ko'rinishda yoziladi — har bayt aynan ikki belgi: 0x00 dan 0xff gacha (Sanoq tizimlari). PNG imzosining boshi 137 — hex'da 0x89, keyingi uchtasi 0x50 0x4e 0x47.

2.2 Birinchi Uint8Array

Uint8Array — har katagi bitta bayt bo'lgan typed array. Nomi o'qiladi: Unsigned (ishorasiz, ya'ni manfiy yo'q) int (butun) 8 (bit).

js
const imzo = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);

console.log(imzo); // Uint8Array(4) [ 137, 80, 78, 71 ]
console.log(imzo.length); // 4
console.log(imzo[1]); // 80

Hex'da yozdik — konsol o'nlik sonda ko'rsatdi. Ikkalasi bitta son: 0x50 va 80 bir xil. Node turini va uzunligini oldiga yozadi: Uint8Array(4).

Uzunlik bilan yaratsangiz, hamma katak 0 bo'ladi — teshik emas (Teshikli massivlar darsidagi new Array(3) dan farqi shu):

js
const katak = new Uint8Array(3);

console.log(katak); // Uint8Array(3) [ 0, 0, 0 ]

2.3 Massivga o'xshaydi, lekin massiv emas

Typed array — oldingi darsdagi massivga o'xshash oilaning a'zosi. Unda length va indekslar bor. Ko'p tanish metodlar ham bor: map, filter, reduce, forEach, includes, slice, join. Lekin Array.isArray false deydi, va uzunlikni o'zgartiradigan metodlar yo'q:

js
const baytlar = new Uint8Array(3);

baytlar.push(7);
text
TypeError: baytlar.push is not a function

Tarjimasi: "baytlar.push — funksiya emas". push, pop, splice yo'q — kassetaga yangi katak qo'shib bo'lmaydi. Chegaradan tashqariga yozish esa jimgina e'tiborsiz qoladi:

js
const baytlar = new Uint8Array(3);
baytlar[5] = 9;

console.log(baytlar); // Uint8Array(3) [ 0, 0, 0 ]
console.log(baytlar.length); // 3

Oddiy massivda [5] = 9 teshik yaratib, massivni cho'zardi. Typed array'da esa — hech narsa. Teshik ham, cho'zilish ham yo'q.

Tekshirib ko'ring: new Uint8Array(2) dan keyin Array.isArray(x) va x.length nima qaytaradi? Oddiy massivga qanday aylantirasiz?

Javob

false va 2. Oddiy massivga — oldingi darsdagi usul: Array.from(x) yoki [...x]. Typed array iterable, shuning uchun spread ham ishlaydi.

3. Chegaralar: toshish va yaxlitlash

3.1 0–255 dan tashqari son

Uint8Array katagiga 256 yoki -1 yozsangiz nima bo'ladi? Xato chiqmaydi — son "aylanib" o'tadi:

js
const b = new Uint8Array(4);
b[0] = 255;
b[1] = 256;
b[2] = -1;
b[3] = 300;

console.log(b); // Uint8Array(4) [ 255, 0, 255, 44 ]

Bu — toshish (overflow). Avtomobil spidometridagi probeg hisoblagichini eslang: 999 999 dan keyin 000 000 ga qaytadi. Bayt ham shunday: 255 dan keyin 0 keladi. 256 — 0, 300 — 300 - 256 = 44, -1 — 255. Qoidani oddiy so'z bilan aytsak: sig'maydigan songa 256 ni qo'shib yoki ayirib, uni 0–255 oralig'iga "qaytaradi" (-1 + 256 = 255). Bitlar tilida esa — sonning faqat oxirgi sakkiz biti olinadi, qolgani tashlanadi.

Rasm bilan ishlaganda bu yomon: piksel yorqinligi 250 ga 10 qo'shsangiz, eng yorug' nuqta to'satdan qora (4) bo'ladi. Shuning uchun maxsus "qisuvchi" tur bor — Uint8ClampedArray. U toshib o'tmaydi, chegarada to'xtaydi va kasrni yaxlitlaydi:

js
const piksel = new Uint8ClampedArray([300, -5, 12.7]);

console.log(piksel); // Uint8ClampedArray(3) [ 255, 0, 13 ]

300 — 255 da to'xtadi, -5 — 0 da. Brauzerdagi <canvas> rasm piksellarini aynan shu turda beradi.

3.2 map ham toshadi

Typed array'ning map metodi xuddi shu turdagi yangi typed array qaytaradi. Natija sig'masa — u ham toshadi:

js
const yorugligi = new Uint8Array([200, 240, 250]);

const yangi = yorugligi.map((x) => x + 10);
console.log(yangi); // Uint8Array(3) [ 210, 250, 4 ]

250 + 10 = 260 → 4. Oddiy son kerak bo'lsa, avval oddiy massivga o'ting: Array.from(yorugligi, (x) => x + 10) — [ 210, 250, 260 ].

3.3 Turlar oilasi

Uint8Array — oilaning bir a'zosi. Qolganlari katak o'lchami va son turida farq qiladi:

Tur Katak Qiymatlar
Int8Array 1 bayt -128 … 127
Uint8Array, Uint8ClampedArray 1 bayt 0 … 255
Int16Array / Uint16Array 2 bayt -32 768 … 32 767 / 0 … 65 535
Int32Array / Uint32Array 4 bayt ±2,1 mlrd / 0 … 4,29 mlrd
Float16Array 2 bayt kasr, ~3 xona aniqlik
Float32Array 4 bayt kasr, ~7 xona aniqlik
Float64Array 8 bayt oddiy JS soni (number)
BigInt64Array / BigUint64Array 8 bayt BigInt

"Int" — ishorali (manfiy bo'lishi mumkin), "Uint" — ishorasiz. Raqam — bitlar soni. Har turdagi bitta katak necha bayt ekanini BYTES_PER_ELEMENT aytadi:

js
console.log(Uint8Array.BYTES_PER_ELEMENT); // 1
console.log(Float64Array.BYTES_PER_ELEMENT); // 8
console.log(new Int32Array(3).byteLength); // 12

byteLength — butun typed array xotirada necha bayt egallashi: 3 katak × 4 bayt = 12.

Butun turlarga kasr yozilsa, kasr qismi tashlab yuboriladi (yaxlitlanmaydi):

js
console.log(new Int32Array([1.9, -1.9])); // Int32Array(2) [ 1, -1 ]
console.log(new Int8Array([127, 128])); // Int8Array(2) [ 127, -128 ]

1.9 → 1, -1.9 → -1. Int8Array da esa 128 sig'madi va manfiy tomonga aylanib o'tdi: -128.

Tekshirib ko'ring: new Uint8Array([257, 3.99]) qanday chiqadi? Uint8ClampedArray da-chi?

Javob

Uint8Array(2) [ 1, 3 ] — 257 aylanib 1 bo'ldi, 3.99 ning kasr qismi tashlandi. Uint8ClampedArray(2) [ 255, 4 ] — 257 chegarada to'xtadi, 3.99 esa yaxlitlandi. Ikki tur ikki xil qoida bilan ishlaydi.

4. Kasr turlari va Float16Array

4.1 Aniqlik — xotira evaziga

JavaScript'ning oddiy soni — 8 baytlik kasr son (Number turi). Float64Array aynan shunday katak. Float32Array — ikki baravar kichik, lekin aniqligi kamroq:

js
console.log(new Float64Array([0.1])[0]); // 0.1
console.log(new Float32Array([0.1])[0]); // 0.10000000149011612

0.1 ni 4 baytga sig'dirib bo'lmadi — eng yaqin son saqlandi. O'qiganda u 8 baytlik JS soniga qaytadi va "dum" ko'rinib qoladi.

Nega aniqligi past turni tanlashadi? Xotira uchun. 3D o'yindagi millionlab nuqta yoki sun'iy intellekt modelidagi milliardlab son — har birida 4 bayt tejash gigabaytlarni tejaydi. Ekrandagi nuqtaning o'rni uchun 7 xona aniqlik yetarli.

4.2 Float16Array — yarim aniqlik

2025-yilda JavaScript'ga yana kichikroq tur qo'shildi — Float16Array, har katagi 2 bayt. U grafika kartalari va sun'iy intellekt modellarida keng ishlatiladigan formatga mos keladi.

js
const yarim = new Float16Array([0.1, 65504, 70000]);

console.log(yarim[0]); // 0.0999755859375
console.log(yarim[1]); // 65504
console.log(yarim[2]); // Infinity
console.log(Math.f16round(0.1)); // 0.0999755859375

Aniqlik — taxminan uch xona. Eng katta son — 65 504; undan kattasi Infinity bo'ladi. Math obyekti darsida va'da qilgan Math.f16round — oddiy sonni xuddi shu formatga yaxlitlab ko'rsatadi: Float16Array ga yozsangiz, aynan shu son saqlanadi.

Float16Array 2025-yil aprelidan beri barcha asosiy brauzerlarda bor (Chrome 135, Firefox 129, Safari 18.2 — "Baseline 2025"). Node 24 da ham ishlaydi.

5. ArrayBuffer: xotira va unga "ko'zoynaklar"

5.1 Xotiraning o'zi

Typed array ichida yana bir obyekt yashiringan — ArrayBuffer. Bu — xom xotira bo'lagi: bir necha bayt, xolos. Unda "son", "tur" degan tushuncha yo'q. Uni to'g'ridan-to'g'ri o'qib ham, yozib ham bo'lmaydi:

js
const xotira = new ArrayBuffer(4);

console.log(xotira.byteLength); // 4
console.log(xotira[0]); // undefined

xotira[0] — undefined. ArrayBuffer — shunchaki "4 bayt joy". U bilan ishlash uchun unga ko'rinish (view) kerak: typed array yoki DataView.

Hayotdan o'xshatish: qog'ozga yozilgan 2026 raqamlari. Ularni to'rtta alohida raqam deb o'qish mumkin — 2, 0, 2, 6. Yoki bitta son deb — ikki ming yigirma olti. Qog'oz bitta, yozuv o'zgarmadi — faqat qanday o'qishni tanladingiz. ArrayBuffer — qog'oz, typed array — o'qish usuli ("ko'zoynak").

5.2 Bir xotira, ikki ko'rinish

Bitta ArrayBuffer ga ikki xil typed array bilan qaraymiz:

js
const xotira = new ArrayBuffer(4);
const baytlar = new Uint8Array(xotira);
const butun = new Uint32Array(xotira);

baytlar[0] = 232;
baytlar[1] = 3;

console.log(butun[0]); // 1000
console.log(butun.length); // 1

baytlar orqali ikkita baytni yozdik, butun orqali esa bitta son o'qidik — 1000. Ikkalasi bitta xotiraga qaraydi: biri uni 4 ta bir baytli katak deb ko'radi, ikkinchisi — bitta to'rt baytli son.

Sxemada kuzating: to'rt bayt — bitta ArrayBuffer, Uint8Array va Uint32Array — unga qaraydigan ikki ko'rinish:

flowchart TB
  U8["Uint8Array: 4 ta katak — 232, 3, 0, 0"]
  subgraph X["ArrayBuffer — 4 bayt"]
    direction LR
    B0["0: e8"] --- B1["1: 03"] --- B2["2: 00"] --- B3["3: 00"]
  end
  U32["Uint32Array: 1 ta katak — 1000"]
  U8 -- "har baytni alohida" --> X
  U32 -- "4 baytni bitta son" --> X

Nega aynan 1000? Ko'p baytli sonda har keyingi bayt 256 barobar "og'irroq" — xuddi o'nlik sonda har keyingi xona 10 barobar og'irroq bo'lgani kabi. Bizda katta bayt — 3, kichigi — 232:

js
console.log(3 * 256 + 232); // 1000
console.log((1000).toString(16)); // 3e8

Hex'da 1000 — 0x03e8: katta bayt 03, kichik bayt e8 (232). Lekin xotirada ular teskari tartibda turibdi: avval kichik qismi e8, keyin 03. Bu tartibning nomi bor — keyingi bo'limda.

5.3 subarray va slice

Typed array'ning bir qismi kerak bo'lsa, ikki metod bor — va ular jiddiy farq qiladi:

js
const imzo = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);

const oyna = imzo.subarray(1, 3);
const nusxa = imzo.slice(1, 3);

oyna[0] = 0;

console.log(imzo[1]); // 0
console.log(nusxa[0]); // 80

subarray — yangi ko'rinish, xotira o'sha. Unga yozsangiz, asl typed array ham o'zgaradi. slice esa xotirani nusxalaydi — oddiy massivdagi slice kabi. Katta fayllarda subarray tez (hech narsa nusxalanmaydi), lekin Havola semantikasi darsidagi tuzoq qaytadi: "nusxa" deb o'ylagan narsangiz aslida o'sha xotira.

Tekshirib ko'ring: const a = new Uint8Array(4); const b = new Uint8Array(a.buffer); b[0] = 5; — a[0] nima? buffer xususiyati nima beradi deb o'ylaysiz?

Javob

5. a.buffer — a ning ostidagi ArrayBuffer. b o'sha xotiraga yangi ko'rinish yaratdi, shuning uchun b ga yozilgani a da ko'rinadi.

6. DataView va bayt tartibi

6.1 Endianness

Bir necha baytli sonni xotiraga ikki xil tartibda yozish mumkin. 1000 = 0x03e8 ni olaylik:

  • Big-endian — "katta uchi oldinda": 03 e8. Biz sonlarni qog'ozga shunday yozamiz: katta xona chapda.
  • Little-endian — "kichik uchi oldinda": e8 03. Deyarli barcha zamonaviy kompyuter va telefon protsessorlari xotirada shunday saqlaydi.

Endianness (bayt tartibi) — ko'p baytli son xotirada qaysi tartibda turishi. Sana yozishga o'xshaydi: "2026-10-04" va "04.10.2026" — sana bir xil, tartib boshqa. Kim yozgani va kim o'qishini bilmasangiz, 04-oktabrni 10-aprel deb o'qib qo'yishingiz mumkin.

Typed array'lar har doim kompyuterning o'z tartibida ishlaydi — shuning uchun yuqorida e8 03 chiqdi. Lekin fayl formatlari va tarmoq protokollari tartibni o'zi belgilaydi. PNG ichidagi sonlar, masalan, big-endian. Boshqa kompyuterdan kelgan baytlarni to'g'ri o'qish uchun tartibni aniq ko'rsatish kerak.

6.2 DataView

DataView — tur va tartibni har o'qishda o'zingiz tanlaydigan ko'rinish:

js
const xotira = new ArrayBuffer(4);
const dv = new DataView(xotira);
const baytlar = new Uint8Array(xotira);

dv.setUint32(0, 1000);
console.log(baytlar); // Uint8Array(4) [ 0, 0, 3, 232 ]

dv.setUint32(0, 1000, true);
console.log(baytlar); // Uint8Array(4) [ 232, 3, 0, 0 ]

baytlar — o'sha xotiraga ikkinchi ko'rinish: u har yozuvdan keyin baytlarni ko'rsatadi. setUint32(joy, son) — joy baytidan boshlab 4 baytli son yozadi. Uchinchi argument berilmasa — big-endian (0, 0, 3, 232). true — little-endian (232, 3, 0, 0). O'qish ham xuddi shunday: getUint32(joy, kichikOldinmi).

Tartib adashsa nima bo'lishini ko'ring:

js
const dv = new DataView(new ArrayBuffer(4));
dv.setUint32(0, 1000);

console.log(dv.getUint32(0)); // 1000
console.log(dv.getUint32(0, true)); // 3892510720

Big-endian yozib, little-endian o'qisak — 1000 o'rniga qariyb 3,9 milliard. Xato xabari yo'q. Fayl yoki tarmoqdan "g'alati ulkan son" kelsa — birinchi gumon: bayt tartibi.

DataView da har tur uchun juft metodlar bor: getInt8/setInt8, getUint16/setUint16, getFloat32/setFloat32, getBigInt64 va boshqalar. Ularning hammasida tartib argumenti bir xil ishlaydi (bir baytlilardan tashqari — bitta baytda tartib yo'q).

Tekshirib ko'ring: dv.setUint16(0, 0x0102) dan keyin new Uint8Array(dv.buffer) ning birinchi ikki bayti qanday? setUint16(0, 0x0102, true) dan keyin-chi?

Javob

1, 2 — big-endian, katta qism (01) oldinda. true bilan — 2, 1. Son bir xil, faqat baytlar tartibi teskari.

7. Matn ↔ baytlar

7.1 TextEncoder va TextDecoder

Tarmoq orqali matn ham baytlar bo'lib ketadi. Matnni baytlarga aylantirish — kodlash (encoding). Bugungi standart — UTF-8. Unicode va emoji darsida ko'rgan edik: lotin harfi bitta joy egallaydi, boshqa belgilar ko'proq. UTF-8 da ham shunday:

js
const baytlar = new TextEncoder().encode("Osh ✓");

console.log(baytlar.length); // 7
console.log(new TextEncoder().encode("ош").length); // 4
console.log(new TextDecoder().decode(baytlar)); // Osh ✓

"Osh" va bo'sh joy — 4 bayt, ✓ belgisi esa yolg'iz o'zi — 3 bayt. Kirill harflari 2 baytdan. TextEncoder doim UTF-8 da Uint8Array qaytaradi, TextDecoder esa teskarisini qiladi. Ikkalasi brauzerda ham, Node'da ham tayyor.

Shuning uchun "matn uzunligi" va "baytlar soni" — har xil narsa. Ma'lumotlar bazasida "255 bayt" chegarasi bo'lsa, 255 ta kirill harfi unga sig'maydi.

7.2 Hex va Base64

Baytlarni odam o'qiydigan matnga aylantirishning ikki mashhur usuli bor:

  • Hex — har bayt ikki belgi: 89504e47. Xesh summalar, ranglar (#ff8800), fayl imzolari shunday yoziladi.
  • Base64 — baytlarni lotin harflari, raqamlar, + va / bilan yozish. Email ilovalari, data: URL'lar, tokenlar shu ko'rinishda. Hex'dan ixchamroq: 3 bayt — 4 belgi.

Hex'ni o'zimiz yasay olamiz — tanish vositalar bilan:

js
const imzo = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);

const hex = Array.from(imzo, (b) => b.toString(16).padStart(2, "0"));
console.log(hex.join("")); // 89504e47

toString(16) — sonni o'n oltilik satrga (Sanoq tizimlari), padStart(2, "0") — bir xonali a ni 0a qiladi (Kesish va to'ldirish). Array.from oddiy massiv qaytaradi — typed array'ning map i satr qaytara olmasdi.

2025-yilda bu ishlar uchun tayyor metodlar qo'shildi (ES2026 standarti): toHex(), Uint8Array.fromHex(), toBase64(), Uint8Array.fromBase64(). Ular Chrome 140, Firefox 133 va Safari 18.2 da bor (Baseline ma'lumoti: "Baseline 2025", 2025-yil sentabr). Node 24 da hali yo'q — shuning uchun natija oynasida, brauzerda ko'ramiz. Konsol paneliga qarang:

html
<p>Konsolni oching: baytlar → hex → Base64 → baytlar.</p>
<script>
  const imzo = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);
  console.log(imzo.toHex());

  const salom = new TextEncoder().encode("Bahor");
  const b64 = salom.toBase64();
  console.log(b64);

  const qaytgan = Uint8Array.fromBase64(b64);
  console.log(new TextDecoder().decode(qaytgan));
  console.log(Uint8Array.fromHex("0d0a").join(" "));
</script>

Konsolda:

text
89504e47
QmFob3I=
Bahor
13 10

"Bahor" so'zining 5 bayti Base64 da 8 belgi bo'ldi (oxiridagi = — to'ldiruvchi). fromBase64 uni aynan o'sha baytlarga qaytardi. Eski brauzerlarni ham qo'llash kerak bo'lsa — yuqoridagi qo'lda yozilgan hex funksiyasi yoki eski btoa/atob funksiyalari ishlatiladi.

Diqqat: Base64 — shifrlash emas. U faqat ko'rinishni o'zgartiradi, istalgan odam uni bir qator bilan ortga qaytaradi. Parolni "Base64 qildim, endi xavfsiz" deyish — jiddiy xato. Shifrlash — boshqa mavzu, uni xavfsizlik qismlarida ko'ramiz.

8. O'lchami o'zgaradigan va ko'chiriladigan xotira

Odatda ArrayBuffer ning hajmi yaratilganda qotadi. 2024-yildan boshlab ikki yangi imkoniyat bor (Baseline ma'lumoti: "Baseline 2024").

O'lchami o'zgaradigan (resizable) bufer. Yaratishda eng katta hajmni ko'rsatasiz, keyin resize bilan kattalashtirasiz yoki kichraytirasiz:

js
const xotira = new ArrayBuffer(2, { maxByteLength: 8 });
const baytlar = new Uint8Array(xotira);

console.log(baytlar.length); // 2
xotira.resize(6);
console.log(baytlar.length); // 6

Typed array uzunlik bermasdan yaratilgani uchun u bufer bilan birga o'sdi. Fayl qismlari tarmoqdan asta-sekin kelganda qulay: har safar yangi bufer yaratib, eskisini ko'chirish shart emas.

Ko'chirish (transfer). transfer() xotirani yangi ArrayBuffer ga o'tkazadi — nusxa olmasdan. Eskisi esa bo'shab qoladi ("detached"):

js
const eski = new ArrayBuffer(4);
const korinish = new Uint8Array(eski);
korinish[0] = 7;

const yangi = eski.transfer();

console.log(eski.detached, eski.byteLength); // true 0
console.log(korinish.length); // 0
console.log(new Uint8Array(yangi)[0]); // 7

Ma'lumot yangi ga o'tdi. eski va unga qaragan korinish endi bo'sh. Bu — "ushbu xotira endi menga tegishli emas" degan kafolat. Brauzerda katta ma'lumotni fon oqimiga yuborganda aynan shunday ko'chiriladi. Fon oqimi (Web Worker) — sahifa bilan yonma-yon ishlaydigan alohida skript; uni keyingi qismlarda o'rganamiz, hozir bilish shart emas.

9. Ko'p uchraydigan xatolar

9.1 push is not a function

Typed array uzunligi qat'iy. Tuzatish: kerakli uzunlikni oldindan biling yoki oddiy massivda yig'ib, oxirida new Uint8Array(massiv) qiling.

9.2 Jim toshish

Uint8Array ga 256 yozilsa — 0, map natijasi ham toshadi. Xato xabari yo'q. Tuzatish: sig'maydigan hisobni oddiy massivda qiling (Array.from(b, ...)), piksellar uchun — Uint8ClampedArray.

9.3 Bayt tartibi adashgan

Sonlar "g'alati ulkan" chiqsa — little/big-endian adashgan. Tuzatish: fayl yoki protokol hujjatidan tartibni toping va DataView ning oxirgi argumentini aniq yozing.

9.4 subarray ni nusxa deb o'ylash

subarray ga yozilgan narsa asl massivda ham o'zgaradi. Tuzatish: mustaqil nusxa kerak bo'lsa — slice.

9.5 Typed array'ni muzlatish

Oddiy obyekt va massivni o'zgarmas qilish usulini Obyektni himoyalash darsida o'rganamiz. Typed array'da u ishlamaydi:

js
Object.freeze(new Uint8Array(2));
text
TypeError: Cannot freeze array buffer views with elements

Tarjimasi: "elementli bufer ko'rinishlarini muzlatib bo'lmaydi". Baytlar xotirasi har doim o'zgaruvchan. O'zgarmasligi kerak bo'lsa — nusxasini bering (slice).

10. Mashqlar

1-mashq (oson): RGB rang

#ff8800 rangining uch qismini (qizil, yashil, ko'k) Uint8Array ga yozing va konsolga chiqaring. So'ng har qismga 100 qo'shib, natijani Uint8ClampedArray da hisoblang. Ishora: 0xff — hex son (Sanoq tizimlari); typed array'ning map i xuddi shu turni qaytaradi.

Yechim
js
const rang = new Uint8Array([0xff, 0x88, 0x00]);
console.log(rang); // Uint8Array(3) [ 255, 136, 0 ]

const yorugroq = new Uint8ClampedArray(rang).map((x) => x + 100);
console.log(yorugroq); // Uint8ClampedArray(3) [ 255, 236, 100 ]

new Uint8ClampedArray(rang) — mavjud typed array'dan nusxa, boshqa turda. Qizil allaqachon 255 edi — chegarada qoldi. Uint8Array da map qilganimizda esa qizil 99 ga aylanib o'tardi (355 − 256).

2-mashq (o'rta): Tarozi xabari

«Bahor» oshxonasidagi elektron tarozi har o'lchovni 4 baytda yuboradi: grammdagi og'irlik, little-endian, ishorasiz butun son. Kelgan baytlar: [0x10, 0x27, 0x00, 0x00]. Og'irlikni DataView bilan o'qing. Ishora: new DataView(baytlar.buffer) va getUint32(0, true).

Yechim
js
const baytlar = new Uint8Array([0x10, 0x27, 0x00, 0x00]);
const dv = new DataView(baytlar.buffer);

console.log(dv.getUint32(0, true)); // 10000
console.log(dv.getUint32(0)); // 270991360

To'g'ri tartibda — 10 000 gramm, ya'ni 10 kg guruch. Tartib adashsa — 270 million gramm. Ikkinchi qatorni ataylab qo'shdik: xato javob qanchalik "ishonchsiz" ko'rinishini eslab qoling.

3-mashq (qiyin): O'z hexdan funksiyangiz

hexdan(matn) funksiyasini yozing: "89504e47" kabi satrdan Uint8Array qaytarsin. Toq uzunlikdagi satr uchun bo'sh Uint8Array qaytarsin. So'ng natijani hex'ga qaytarib, asl satr bilan solishtiring. Ishora: ikki belgidan bitta bayt — Number.parseInt(qism, 16) (Matn ↔ son); Array.from({ length: n }, ...) — oldingi darsdan.

Yechim
js
function hexdan(matn) {
  if (matn.length % 2 !== 0) {
    return new Uint8Array(0);
  }
  const sonlar = Array.from({ length: matn.length / 2 }, (_, i) =>
    Number.parseInt(matn.slice(i * 2, i * 2 + 2), 16),
  );
  return new Uint8Array(sonlar);
}

function hexga(baytlar) {
  return Array.from(baytlar, (b) => b.toString(16).padStart(2, "0"))
    .join("");
}

const baytlar = hexdan("89504e47");
console.log(baytlar); // Uint8Array(4) [ 137, 80, 78, 71 ]
console.log(hexga(baytlar) === "89504e47"); // true
console.log(hexdan("abc").length); // 0

Array.from({ length: 4 }, ...) — har ikki belgi uchun bitta qadam. slice(i * 2, i * 2 + 2) — i-juftlikning ikki belgisi. Brauzerda yangi Uint8Array.fromHex ham bor, lekin u noto'g'ri satrda xato tashlaydi — biz esa bo'sh natija qaytarishni tanladik. Bu — funksiya "shartnomasi": noto'g'ri kirishda nima bo'lishini siz hal qilasiz.

4-mashq: Mashqlar qadami — fayl imzosini aniqlash

Bu mavzu ham vazifalar ga tegmaydi — qadam mashqlar reposida. kurs/mashqlar/10/11-baytlar/imzo.js faylini yarating.

faylTuri(baytlar) funksiyasini yozing. U Uint8Array oladi va birinchi baytlariga qarab tur nomini qaytaradi:

Tur Boshidagi baytlar (hex)
"png" 89 50 4e 47
"jpeg" ff d8 ff
"pdf" 25 50 44 46 (bu — %PDF matni)

Boshqa holatda — "noma'lum". Uch to'g'ri va ikki "noto'g'ri" holatni sinang: bo'sh Uint8Array va faqat ikki baytli fayl.

Yechim
js
const imzolar = [
  { tur: "png", baytlar: [0x89, 0x50, 0x4e, 0x47] },
  { tur: "jpeg", baytlar: [0xff, 0xd8, 0xff] },
  { tur: "pdf", baytlar: new TextEncoder().encode("%PDF") },
];

function boshlanadimi(baytlar, imzo) {
  if (baytlar.length < imzo.length) {
    return false;
  }
  return Array.from(imzo).every((b, i) => baytlar[i] === b);
}

function faylTuri(baytlar) {
  const topildi = imzolar.find(
    (x) => boshlanadimi(baytlar, x.baytlar),
  );
  return topildi ? topildi.tur : "noma'lum";
}

const sinovlar = [
  new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a]),
  new Uint8Array([0xff, 0xd8, 0xff, 0xe0]),
  new TextEncoder().encode("%PDF-1.7"),
  new Uint8Array(0),
  new Uint8Array([0x89, 0x50]),
];

for (const baytlar of sinovlar) {
  console.log(faylTuri(baytlar));
}

Konsolda:

text
png
jpeg
pdf
noma'lum
noma'lum

PDF imzosini hex bilan emas, TextEncoder bilan yozdik — chunki u aynan %PDF matni. boshlanadimi dagi uzunlik tekshiruvi muhim: usiz ikki baytli fayl uchun baytlar[2] — undefined, taqqoslash false beradi va natija to'g'ri chiqadi, lekin tasodifan. Shartni ochiq yozish — niyatni ko'rsatadi.

Ishga tushiring va commit qiling:

bash
cd ~/kurs/mashqlar
node 10/11-baytlar/imzo.js
git add 10/11-baytlar
git commit -m "10/11: fayl imzosini baytlardan aniqlashni qo'sh"

11. Real ishda

  • Fayl yuklash va xavfsizlik. Saytga rasm yuklanganda server faqat nomdagi .png ga ishonmaydi — 4-mashqdagi kabi birinchi baytlarni tekshiradi. Hujumchi virus.exe ni rasm.png deb nomlashi mumkin, baytlar esa yolg'on gapirmaydi.
  • Brauzer API'lari. fetch javobining arrayBuffer(), fayl o'qish, <canvas> piksellari (Uint8ClampedArray), WebSocket'dagi binar xabarlar, Web Audio ovoz to'lqinlari — hammasi typed array. Ularni keyingi qismlarda ko'rasiz.
  • Node.js. Node'dagi Buffer — Uint8Array ning "kengaytirilgan" turi. Fayllar, tarmoq, shifrlash — hammasi u orqali (Node.js qismi).
  • Sun'iy intellekt va grafika. Model og'irliklari va 3D nuqtalar Float32Array/Float16Array da saqlanadi — millionlab son bitta ixcham xotirada.
  • Intervyu. "ArrayBuffer va typed array farqi?", "endianness nima?", "Base64 shifrlashmi?" — backend va frontend intervyularida uchraydi.

Xulosa

  • Typed array — bir xil turdagi sonlar uchun qat'iy o'lchamli massiv: Uint8Array, Int32Array, Float64Array, Float16Array.
  • Butun turlar toshadi (256 → 0), Uint8ClampedArray chegarada to'xtaydi; kasr turlari aniqlikni xotira evaziga yo'qotadi.
  • ArrayBuffer — xom xotira; typed array va DataView — unga qaraydigan ko'rinishlar. subarray xotirani bo'lishadi, slice nusxalaydi.
  • Ko'p baytli son tartibi — endianness; tashqi ma'lumotni DataView bilan tartibni aniq ko'rsatib o'qing.
  • TextEncoder/TextDecoder — matn ↔ UTF-8 baytlar; toHex/toBase64 — yangi (ES2026) tayyor metodlar, Base64 shifrlash emas.

Keyingi dars: Getter va setter — obyektlarga qaytamiz: o'qilganda hisoblanadigan va yozilganda tekshiriladigan xususiyatlar yasaymiz.

Manbalar

  • MDN: "JavaScript typed arrays", "ArrayBuffer", "DataView", "Float16Array" — developer.mozilla.org
  • MDN: "Uint8Array.prototype.toHex()", "Uint8Array.fromBase64()" — developer.mozilla.org
  • web-features 3.40.0: float16array, uint8array-base64-hex, resizable-buffers, transferable-arraybuffer
  • ECMAScript 2026 Language Specification: "TypedArray Objects", "ArrayBuffer Objects" — tc39.es/ecma262
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript typed arrays: ArrayBuffer, Uint8Array va binar ma'lumot bilan ishlash — IlmHamroh