19-bo‘lim

Modullar va zamonaviy JavaScript

import va export, Map va Set, sinflar, getter va setter, ixtiyoriy zanjir, spread va boshqa zamonaviy imkoniyatlar.

🕑 17 daqiqa o‘qish 📄 658 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Modul - alohida fayl
  2. Map - istalgan kalitli lug'at
  3. Set - takrorlanmaydigan to'plam
  4. Sinflar
  5. Ixtiyoriy zanjir va nullish
  6. Spread va rest
  7. Foydali yangi metodlar
  8. Yorliqli shablon (tagged template)
  9. Xulosa

Loyiha o'sgach kodni fayllarga bo'lish kerak bo'ladi. Bu bo'limda modullar va oxirgi yillarda qo'shilgan foydali imkoniyatlarni ko'ramiz.

Modul - alohida fayl #

Modullar bir necha faylni talab qiladi, shuning uchun bu misollar namuna sifatida keltirilgan.

JavaScript
// matematika.js

export const PI = 3.14159;

export function kvadrat(son) {
    return son * son;
}

export function kub(son) {
    return son * son * son;
}

// har faylda bitta standart eksport bo'lishi mumkin
export default function yigindi(...sonlar) {
    return sonlar.reduce((a, b) => a + b, 0);
}
JavaScript
// asosiy.js

import yigindi, { PI, kvadrat } from "./matematika.js";
import { kub as kubga } from "./matematika.js";
import * as matematika from "./matematika.js";

console.log(PI);                    // 3.14159
console.log(kvadrat(4));            // 16
console.log(kubga(3));              // 27
console.log(yigindi(1, 2, 3));      // 6
console.log(matematika.kvadrat(5)); // 25
HTML
<!-- Brauzerda type="module" kerak -->
<script type="module" src="asosiy.js"></script>
Nomlangan va standart eksport
NomlanganStandart
SoniCheksizBittasi
Importimport { nom }import nom
Nom o'zgartirishas kerakIxtiyoriy
Avtomatik to'ldirishIshlaydiIshlamaydi

Ko'p jamoalar faqat nomlangan eksportni ishlatadi:

JavaScript
export function foydalanuvchiOlish() { }
export function foydalanuvchiSaqlash() { }

Sabab: standart eksportni har faylda turlicha nomlash mumkin, bu chalkashlik tug'diradi:

JavaScript
import A from "./foydalanuvchi.js";
import B from "./foydalanuvchi.js";      // bir xil narsa, boshqa nom

Nomlangan eksportda esa nom bir xil qoladi va tahrirlagich uni avtomatik topadi.

Modul fayllarini file:// orqali ochib bo'lmaydi
Natija
Access to script at 'file:///.../asosiy.js' from origin 'null'
has been blocked by CORS policy

Modullar HTTP orqali yuklanishi shart. HTML faylni ikki marta bosib ochsangiz ishlamaydi.

Yechim - oddiy server ishga tushiring:

Terminal
npx serve
python3 -m http.server
php -S localhost:8000

Modullarning boshqa xususiyatlari:

  • Har doim strict rejimda ishlaydi;
  • O'z ko'lamiga ega - global o'zgaruvchi yaratmaydi;
  • Bir marta yuklanadi va keshlanadi;
  • defer kabi ishlaydi - HTML tayyor bo'lgach bajariladi;
  • Yuqoriga await qo'yish mumkin (top-level await).

Node.js da .mjs kengaytmasi yoki package.json da "type": "module" kerak. Aks holda Node require ni kutadi.

Map - istalgan kalitli lug'at #

JavaScript
const yoshlar = new Map();

yoshlar.set("Husanboy", 25);
yoshlar.set("Malika", 22);

// Obyekt ham kalit bo'la oladi
const kalit = { id: 1 };
yoshlar.set(kalit, "obyekt kaliti");

console.log("get       :", yoshlar.get("Husanboy"));
console.log("has       :", yoshlar.has("Malika"));
console.log("size      :", yoshlar.size);
console.log("Obyekt kalit:", yoshlar.get(kalit));
console.log("Yo'q kalit:", yoshlar.get("Yo'q"));

yoshlar.delete("Malika");
console.log("delete keyin:", yoshlar.size);

// Aylanish - qo'shilish tartibi saqlanadi
const oddiy = new Map([["a", 1], ["b", 2], ["c", 3]]);
for (const [k, q] of oddiy) {
    console.log(`  ${k} -> ${q}`);
}

console.log("Massivga  :", [...oddiy.keys()].join(", "));
Natija
get       : 25
has       : true
size      : 3
Obyekt kalit: obyekt kaliti
Yo'q kalit: undefined
delete keyin: 2
  a -> 1
  b -> 2
  c -> 3
Massivga  : a, b, c
Map yoki oddiy obyekt?
XususiyatObyektMap
Kalit turiFaqat satr va SymbolIstalgan qiymat
HajmObject.keys().length.size
TartibButun sonlar oldinga suriladiQo'shilish tartibi
Meros olingan kalitlarBor (toString va h.k.)Yo'q
Tez-tez qo'shish/o'chirishSekinroqTezroq

Obyektning kutilmagan xatti-harakati:

JavaScript
const obyekt = {};
obyekt[1] = "son";
obyekt["1"] = "satr";
console.log(Object.keys(obyekt));       // ["1"] - bittasi!

Kalit avtomatik satrga aylanadi.

Tartib bilan ham muammo:

JavaScript
const menyu = { "10": "o'n", "2": "ikki", "b": "harf" };
console.log(Object.keys(menyu));        // ["2", "10", "b"]

Butun sonlarga o'xshash kalitlar oldinga suriladi va o'sish tartibida saralanadi.

Qoida: kalitlar oldindan ma'lum bo'lsa - obyekt; dinamik yoki satr bo'lmasa - Map.

Set - takrorlanmaydigan to'plam #

JavaScript
const raqamlar = new Set([1, 2, 2, 3, 3, 3]);

console.log("Hajmi   :", raqamlar.size);
console.log("has(2)  :", raqamlar.has(2));

raqamlar.add(4);
raqamlar.add(4);                    // takror - qo'shilmaydi
console.log("add keyin:", raqamlar.size);

// Massivdagi takrorlarni olib tashlash
const takrorlar = ["a", "b", "a", "c", "b"];
const noyob = [...new Set(takrorlar)];
console.log("Noyob   :", noyob.join(", "));

// To'plamlar ustida amallar
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

const kesishma = [...a].filter((x) => b.has(x));
const birlashma = [...new Set([...a, ...b])];
const ayirma = [...a].filter((x) => !b.has(x));

console.log("Kesishma:", kesishma.join(", "));
console.log("Birlashma:", birlashma.join(", "));
console.log("Ayirma  :", ayirma.join(", "));
Natija
Hajmi   : 3
has(2)  : true
add keyin: 4
Noyob   : a, b, c
Kesishma: 2, 3
Birlashma: 1, 2, 3, 4
Ayirma  : 1

Sinflar #

JavaScript
class Talaba {
    #maxfiyBall = 0;                // shaxsiy maydon

    static soni = 0;                // statik maydon

    constructor(ism, yosh) {
        this.ism = ism;
        this.yosh = yosh;
        Talaba.soni++;
    }

    get ball() {
        return this.#maxfiyBall;
    }

    set ball(qiymat) {
        if (qiymat < 0 || qiymat > 100) {
            throw new RangeError("Ball 0-100 oralig'ida bo'lishi kerak");
        }
        this.#maxfiyBall = qiymat;
    }

    tanishtirish() {
        return `${this.ism}, ${this.yosh} yosh`;
    }

    static taqqoslash(a, b) {
        return b.ball - a.ball;
    }
}

class Magistr extends Talaba {
    constructor(ism, yosh, mavzu) {
        super(ism, yosh);
        this.mavzu = mavzu;
    }

    tanishtirish() {
        return super.tanishtirish() + `, mavzu: ${this.mavzu}`;
    }
}

const birinchi = new Talaba("Husanboy", 25);
birinchi.ball = 92;

const ikkinchi = new Magistr("Aziza", 27, "Sun'iy intellekt");
ikkinchi.ball = 88;

console.log(birinchi.tanishtirish());
console.log(ikkinchi.tanishtirish());
console.log("Ball (getter):", birinchi.ball);
console.log("Talabalar soni:", Talaba.soni);
console.log("Magistr Talabami?:", ikkinchi instanceof Talaba);

try {
    birinchi.ball = 150;
} catch (xato) {
    console.log("Setter tekshiruvi:", xato.message);
}

console.log("Shaxsiy maydon ko'rinadimi?:", Object.keys(birinchi).join(", "));
Natija
Husanboy, 25 yosh
Aziza, 27 yosh, mavzu: Sun'iy intellekt
Ball (getter): 92
Talabalar soni: 2
Magistr Talabami?: true
Setter tekshiruvi: Ball 0-100 oralig'ida bo'lishi kerak
Shaxsiy maydon ko'rinadimi?: ism, yosh
# bilan haqiqiy shaxsiy maydon

Ilgari shaxsiylikni kelishuv bilan belgilashardi:

JavaScript
this._maxfiy = 5;          // "tegmang" degan ishora, lekin ochiq

# esa haqiqiy himoya beradi:

JavaScript
class A {
    #maxfiy = 5;
}

const a = new A();
a.#maxfiy;                 // SyntaxError - tashqaridan murojaat mumkin emas
Object.keys(a);            // [] - ko'rinmaydi
JSON.stringify(a);         // {} - serializatsiyaga tushmaydi

Bu 5-bo'limdagi berkitma (closure) naqshining sinflardagi muqobili - lekin ancha qulayroq.

Shaxsiy metod ham bo'ladi:

JavaScript
class A {
    #ichkiHisob() { }
}

Tekshirish uchun in operatori ishlatiladi:

JavaScript
static bormi(obyekt) {
    return #maxfiy in obyekt;
}

Ixtiyoriy zanjir va nullish #

JavaScript
const foydalanuvchi = {
    ism: "Kamola",
    manzil: { shahar: "Farg'ona" },
    sozlama: { bildirishnoma: false, hajm: 0 }
};

console.log("Mavjud     :", foydalanuvchi.manzil?.shahar);
console.log("Mavjud emas:", foydalanuvchi.ish?.lavozim);
console.log("Chuqur     :", foydalanuvchi.ish?.kompaniya?.nomi);

// Metod chaqirish
console.log("Metod yo'q :", foydalanuvchi.hisobla?.());

// Massiv elementi
const royxat = null;
console.log("Massiv     :", royxat?.[0]);

// ?? bilan birga
console.log("false va ??:", foydalanuvchi.sozlama.bildirishnoma ?? true);
console.log("false va ||:", foydalanuvchi.sozlama.bildirishnoma || true);
console.log("0 va ??    :", foydalanuvchi.sozlama.hajm ?? 14);
console.log("0 va ||    :", foydalanuvchi.sozlama.hajm || 14);

// ??= operatori
const sozlama = { til: null };
sozlama.til ??= "uz";
sozlama.rejim ??= "yorug'";
console.log("??= natijasi:", JSON.stringify(sozlama));
Natija
Mavjud     : Farg'ona
Mavjud emas: undefined
Chuqur     : undefined
Metod yo'q : undefined
Massiv     : undefined
false va ??: false
false va ||: true
0 va ??    : 0
0 va ||    : 14
??= natijasi: {"til":"uz","rejim":"yorug'"}

Spread va rest #

JavaScript
// Massivda
const a = [1, 2];
const b = [3, 4];
console.log("Birlashtirish:", [...a, ...b]);
console.log("Nusxa        :", [...a]);
console.log("Satrdan      :", [..."abc"]);
console.log("Set dan      :", [...new Set([1, 1, 2])]);

// Obyektda
const asos = { x: 1, y: 2 };
console.log("Obyekt spread:", { ...asos, z: 3 });

// Funksiyada
function yigindi(...sonlar) {
    return sonlar.reduce((s, n) => s + n, 0);
}
console.log("Rest         :", yigindi(1, 2, 3, 4));
console.log("Spread argument:", Math.max(...[5, 2, 9]));

// Destrukturizatsiyada rest
const { x, ...qolgani } = { x: 1, y: 2, z: 3 };
console.log("Obyekt rest  :", x, JSON.stringify(qolgani));

const [birinchi, ...boshqalar] = [1, 2, 3, 4];
console.log("Massiv rest  :", birinchi, boshqalar.join(","));
Natija
Birlashtirish: [ 1, 2, 3, 4 ]
Nusxa        : [ 1, 2 ]
Satrdan      : [ 'a', 'b', 'c' ]
Set dan      : [ 1, 2 ]
Obyekt spread: { x: 1, y: 2, z: 3 }
Rest         : 10
Spread argument: 9
Obyekt rest  : 1 {"y":2,"z":3}
Massiv rest  : 1 2,3,4

Foydali yangi metodlar #

JavaScript
// Massiv
console.log("at(-1)     :", [1, 2, 3].at(-1));
console.log("flat       :", [1, [2, [3]]].flat(2));
console.log("flatMap    :", [1, 2].flatMap((x) => [x, x * 10]));
console.log("toSorted   :", [3, 1, 2].toSorted((a, b) => a - b));
console.log("toReversed :", [1, 2, 3].toReversed());
console.log("with       :", [1, 2, 3].with(1, 99));
console.log("findLast   :", [1, 5, 3, 5].findLast((x) => x === 5));

// Satr
console.log("replaceAll :", "a-b-c".replaceAll("-", "+"));
console.log("trimStart  :", JSON.stringify("  x".trimStart()));

// Struktura
const asl = { ichki: { son: 1 } };
const nusxa = structuredClone(asl);
nusxa.ichki.son = 99;
console.log("structuredClone:", asl.ichki.son);
Natija
at(-1)     : 3
flat       : [ 1, 2, 3 ]
flatMap    : [ 1, 10, 2, 20 ]
toSorted   : [ 1, 2, 3 ]
toReversed : [ 3, 2, 1 ]
with       : [ 1, 99, 3 ]
findLast   : 5
replaceAll : a+b+c
trimStart  : "x"
structuredClone: 1
Object.groupBy - juda yangi

ES2024 da guruhlash uchun tayyor metod qo'shilgan:

JavaScript
Object.groupBy([1, 2, 3, 4], (n) => (n % 2 === 0 ? "juft" : "toq"));
// { toq: [1, 3], juft: [2, 4] }

Lekin u Node 21 va 2024-yil o'rtasidan keyingi brauzerlarda paydo bo'lgan - shuning uchun bu yerda ishga tushirilmadi.

Hozircha reduce bilan yozgan ma'qul (7-bo'limdagi kabi):

JavaScript
const guruhlar = sonlar.reduce((natija, n) => {
    const kalit = n % 2 === 0 ? "juft" : "toq";
    (natija[kalit] ??= []).push(n);
    return natija;
}, {});

Yangi imkoniyatni ishlatishdan oldin caniuse.com yoki MDN dagi moslik jadvalini tekshiring - foydalanuvchilaringizning brauzeri uni qo'llab-quvvatlamasligi mumkin.

O'zgartirmaydigan metodlar (ES2023)

sort, reverse va splice asl massivni buzadi. Bu kutilmagan xatolarga olib keladi:

JavaScript
function engKatta(royxat) {
    return royxat.sort((a, b) => b - a)[0];    // ASLINI o'zgartirdi!
}

const ballar = [70, 95, 80];
engKatta(ballar);
console.log(ballar);        // [95, 80, 70] - tartib buzildi

ES2023 dan nusxa qaytaradigan variantlar bor:

Eski (buzadi)Yangi (nusxa)
sort()toSorted()
reverse()toReversed()
splice()toSpliced()
massiv[i] = xwith(i, x)
JavaScript
function engKatta(royxat) {
    return royxat.toSorted((a, b) => b - a)[0];   // xavfsiz
}

Node 20 va 2023-yildan keyingi brauzerlar qo'llab-quvvatlaydi.

Yorliqli shablon (tagged template) #

JavaScript
function xavfsiz(qismlar, ...qiymatlar) {
    return qismlar.reduce((natija, qism, i) => {
        const qiymat = qiymatlar[i - 1];
        const tozalangan = String(qiymat)
            .replaceAll("&", "&amp;")
            .replaceAll("<", "&lt;")
            .replaceAll(">", "&gt;");
        return natija + tozalangan + qism;
    });
}

const foydalanuvchiMatni = "<script>hujum()</script>";
console.log(xavfsiz`Salom, ${foydalanuvchiMatni}!`);

// Oddiy shablon bilan taqqoslash
console.log(`Salom, ${foydalanuvchiMatni}!`);
Natija
Salom, &lt;script&gt;hujum()&lt;/script&gt;!
Salom, <script>hujum()</script>!
Amaliy topshiriq
  1. Ikki fayl yaratib, export va import bilan bog'lang.
  2. Nomlangan va standart eksport farqini tushuntiring.
  3. Map da obyektni kalit sifatida ishlating.
  4. Obyektda 1 va "1" kalitlari bir xil bo'lishini ko'rsating.
  5. Set bilan massivdagi takrorlarni olib tashlang.
  6. Sinf yozib, # bilan shaxsiy maydon qo'shing.
  7. get/set bilan qiymatni tekshiring.
  8. ?. va ?? ni 0 va false qiymatlar bilan sinang.
  9. toSorted va sort farqini isbotlang.
  10. Yorliqli shablon bilan HTML ni tozalang.

Xulosa #

  • export/import kodni fayllarga bo'ladi.
  • Brauzerda type="module" va HTTP server kerak.
  • Modullar strict rejimda ishlaydi va o'z ko'lamiga ega.
  • Nomlangan eksport afzal - nom bir xil qoladi.
  • Map istalgan turdagi kalitni qabul qiladi va tartibni saqlaydi.
  • Obyektda kalit avtomatik satrga aylanadi.
  • Set takrorlarni olib tashlaydi.
  • # bilan haqiqiy shaxsiy maydon yaratiladi.
  • get/set qiymatni tekshirish imkonini beradi.
  • ?? faqat null/undefined da ishlaydi, || esa 0 va "" da ham.
  • toSorted, toReversed, with aslini buzmaydi.
  • Yorliqli shablon bilan xavfsiz HTML yig'iladi.

Keyingi va oxirgi bo'limda hamma bilimni birlashtirib, to'liq ilova yozamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.