Private maydonlar — # belgisi

~10 daq · JavaScript · OOP

Muammodan boshlaylik

Bank hisobini ifodalovchi class yozdingiz. Balansni o'zgartirish uchun yechish metodi bor — u ichida tekshiruv qiladi.

Lekin muammo bor:

const hisob = new BankHisobi("Jasur", 1_000_000);
hisob.yechish(200_000); // ← to'g'ri yo'l, tekshiruv bor

hisob.balans = 999_999_999; // ← bu ham ishlaydi. Hech narsa to'sqinlik qilmayapti.

balans — tashqaridan bevosita o'zgartirilmasligi kerak. Faqat yechish va qo'shish metodlari orqali. Lekin oddiy this.balans = ... bilan e'lon qilingan xususiyatni hech kim to'xtatib qo'ya olmaydi.

Bu — enkapsulatsiya muammosi. Ichki holat (state) tashqaridan yashirilishi kerak.


Enkapsulatsiya nima?

Enkapsulatsiya — ob'ektning ichki ishlarini yashirish. Foydalanuvchiga faqat ruxsat etilgan narsalar ko'rinadi; qanday ishlashi — ichki sir.

Hayotiy o'xshatma

Avtomat kassa mashinasi (ATM). Siz ekranda tugmalarni bosasiz: "500 000 so'm yeching". ATM ichida nima bo'ladi — bilmaysiz va bilishingiz shart emas. Bank ma'lumotlar bazasi, shifrlash, balans tekshiruvi — hammasi ichki. Siz faqat "yechish" tugmasiga borasiz, u sizga ruxsat berilgan operatsiyani bajaradi. Ichki hisoblagichni to'g'ridan o'zingiz o'zgartirishning imkoni yo'q.

# belgisi — o'sha "ichki xona". Tashqaridan kirish mumkin emas.


# belgisi qanday ishlaydi?

# bilan boshlanuvchi xususiyat — faqat class ichidan ko'rinadi. Tashqaridan, hatto bola classdan ham ko'rinmaydi.

class BankHisobi {
  #balans; // ← bu xususiyat class tashqarisida mavjud emas

  constructor(egasi, boshlangich) {
    this.egasi  = egasi;   // ← oddiy, tashqaridan ko'rinadi
    this.#balans = boshlangich; // ← private, faqat ichkaridan
  }

  yechish(miqdor) {
    if (miqdor > this.#balans) {
      throw new Error("Mablag' yetarli emas");
    }
    this.#balans -= miqdor; // ← class ichidan murojaat mumkin ✅
  }

  get balans() {
    return this.#balans; // ← faqat o'qish imkonini beradi
  }
}

const hisob = new BankHisobi("Jasur", 1_000_000);

hisob.yechish(200_000);
console.log(hisob.balans); // 800_000 ✅ — getter orqali o'qildi

hisob.#balans = 999_999;   // ❌ SyntaxError — class tashqarisida ko'rinmaydi
hisob.balans  = 999_999;   // ❌ setter yo'q — o'zgartirib bo'lmaydi

Nima uchun bu muhim?

Oldingi holatda: hisob.balans = 999_999_999 — ishlardi. Tekshiruv chetlab o'tilar edi.

Endi: balansni o'zgartirish uchun faqat yechish yoki qo'shish orqali o'tish kerak. U yerda barcha tekshiruvlar bor. Boshqa yo'l yo'q.


Private metodlar

Metodlar ham private bo'lishi mumkin. Faqat class ichida chaqiriladigan yordamchi metodlar uchun.

Hayotiy o'xshatma

Bankomat ekranda siz ko'radigan tugmalar — oddiy metodlar. Lekin ATM ichida "kartani tekshirish", "bankka ulanish", "operatsiya jurnalini yozish" degan jarayonlar bor — siz bularni ko'rmaysiz, to'g'ridan chaqira olmaysiz. Bular — private metodlar.

class ToLov {
  #kartaRaqami;

  constructor(raqam) {
    this.#kartaRaqami = raqam;
  }

  // Foydalanuvchi ko'radigan yagona narsa:
  info() {
    if (!this.#formatToGrimi()) {
      throw new Error("Karta raqami noto'g'ri");
    }
    return this.#yashir(); // ← tashqariga faqat yashirilgan ko'rinish
  }

  // Ichki yordamchi metodlar — tashqaridan ko'rinmaydi:
  #formatToGrimi() {
    return this.#kartaRaqami.length === 16;
  }

  #yashir() {
    return "*".repeat(12) + this.#kartaRaqami.slice(-4);
  }
}

const karta = new ToLov("1234567890123456");
console.log(karta.info());      // "************3456" ✅
karta.#formatToGrimi();         // ❌ SyntaxError

_ bilan # ning farqi

Bir vaqtlar dasturchilar xususiyat nomi oldiga _ qo'yib "bu private" degan signal berar edi:

class Eski {
  constructor() {
    this._ichki = "meni o'zgartirma!";
  }
}

const ob = new Eski();
ob._ichki = "o'zgartirdim :)"; // ✅ ishlaydi — JavaScript to'xtatmaydi

_ — faqat dasturchi uchun ogohlantirish. JavaScript e'tibor bermaydi. Agar boshqa dasturchi qoidani bilmasa yoki e'tibor bermasa — to'g'ridan o'zgartiradi.

# — tilning o'zi taqiqlaydi. Xohlasang ham o'zgartira olmaysan.


Tez-tez uchraydigan xatolar

Private maydonni oldindan e'lon qilmaslik:

Private maydonlar class tanasida — constructordan tashqarida e'lon qilinishi shart. E'lonsiz foydalanish — sintaksis xatosi.

class Xato {
  constructor() {
    this.#qiymat = 42; // ❌ SyntaxError: Private field '#qiymat' must be declared
  }
}

class ToGri {
  #qiymat; // ✅ avval e'lon
  constructor() {
    this.#qiymat = 42;
  }
}

Bola classdan ota classning private maydoniga murojaat:

Private maydon — faqat u e'lon qilingan classda ko'rinadi. Hatto extends bilan meros olgan bola class ham ko'ra olmaydi.

class Ota {
  #sir = "maxfiy";
}

class Bola extends Ota {
  ochib_ber() {
    return this.#sir; // ❌ SyntaxError — Bola classda #sir yo'q
  }
}

Agar bola class ham foydalanishi kerak bo'lsa — protected pattern (getter orqali):

class Ota {
  #sir = "maxfiy";

  get _sir() { return this.#sir; } // ← bola uchun himoyalangan kirish
}

class Bola extends Ota {
  ochib_ber() {
    return this._sir; // ✅ getter orqali
  }
}

Xulosa

# — chinakam private maydon. Class tashqarisidan ko'rinmaydi, o'zgartirib bo'lmaydi. JavaScript tili o'zi taqiqlaydi.

Enkapsulatsiya — ichki holatni yashirish. Faqat ruxsat etilgan metodlar orqali o'zgartirish. Bu xatolardan himoya qiladi va kodni ishonchli qiladi.

_ kelishuv, # kafolat.


Keyingi dars

33-dars: Mixin pattern