Mundarija (27)
- Bu darsda
- 1. Nega bu kerak?
- 2. Eski yo'l: _ konventsiyasi
- 3. # — haqiqiy private maydon
- 3.1 Birinchi private maydon
- 3.2 Tashqaridan kirishga urinish
- 3.3 Konsolda ko'rinishi
- 4. Getter: o'qishga ruxsat, yozishga — yo'q
- 5. Private metodlar
- 6. Private — klassga tegishli, nusxaga emas
- 6.1 Boshqa nusxaning private maydoni
- 6.2 Begona obyekt va brand check
- 7. _ va #: qachon qaysi biri
- 7.1 Hammasini private qilish kerakmi?
- 8. Ko'p uchraydigan xatolar
- 8.1 E'lon qilinmagan private maydon
- 8.2 Private maydon JSON'da yo'qoladi
- 8.3 Getter bor, metod yo'q — jim tayinlash
- 8.4 kassa["#tushum"] — boshqa xususiyat
- 9. Mashqlar
- 1-mashq (oson): Hisoblagich
- 2-mashq (o'rta): _ dan # ga
- 3-mashq (qiyin): Tamg'ali taqqoslash
- 4-mashq: Vazifalar qadami — #matn va branch'ni yakunlash
- 10. Real ishda
- Xulosa
- Manbalar
JavaScript private maydonlar: # bilan yashirin maydon va metodlar
Qisqacha: Nomi
#bilan boshlangan maydon yoki metod — private (yopiq): unga faqat o'sha klass ichidagi kod murojaat qila oladi. Tashqaridankassa.#tushumyozish fayl ishga tushmasdanSyntaxErrorberadi,Object.keys,JSON.stringifyvaconsole.log(Node'da) uni ko'rmaydi. O'qishga ruxsat kerak bo'lsa — getter.#tushum in objesa obyekt haqiqatan shu klassdan yaratilganini xatosiz tekshiradi.
Bu darsda
#maydonva#metod()yozib, ma'lumotni tashqi o'zgarishdan himoyalay olasiz.- Private maydonni getter orqali "faqat o'qish uchun" ochasiz.
_konventsiyasi va#ning farqini tushuntira olasiz.#maydon in objbilan obyektning haqiqiyligini tekshirasiz.Vazifamatnini private qilib,vazifalarrefaktoringini yakunlaysiz va branch'nimainga qo'shasiz.
Oldin bilishingiz kerak: Class maydonlari, Getter va setter, Strict mode, JSON chuqur.
1. Nega bu kerak?
«Bahor» kassasi uchun klass yozamiz. Kunlik tushum faqat sotuv orqali oshishi kerak:
class Kassa {
tushum = 0;
sotish(summa) {
if (summa > 0) {
this.tushum += summa;
}
}
}
const kassa = new Kassa();
kassa.sotish(35000);
kassa.sotish(-5000); // e'tiborsiz qoldirildi
kassa.tushum = 1000000; // ❌ hech kim to'xtatmadi
console.log(kassa.tushum); // 1000000sotish manfiy summani to'g'ri rad etdi. Lekin uni chetlab o'tish uchun bitta qator yetarli edi: kassa.tushum = 1000000. Tekshiruvni yozdik — lekin u faqat "halol" chaqiruvni tekshiradi. Kodning istalgan joyi — sizniki, jamoadoshingizniki, xato bilan yozilgan qator — tushumni to'g'ridan-to'g'ri o'zgartira oladi.
Haqiqiy kassa apparati qanday ishlaydi? Pul qutisi faqat chek urilganda ochiladi. Otabek qutini qo'l bilan ochib, ichiga "hisob uchun" pul qo'sha olmaydi — apparat bunga yo'l qo'ymaydi. Ekranda esa jami ko'rinib turadi: o'qish mumkin, o'zgartirish — faqat chek orqali.
Bugungi dars aynan shu apparatni yasaydi. Inkapsulyatsiya (encapsulation) — obyektning ichki ma'lumotini yashirib, unga faqat o'zi ruxsat bergan yo'llar (metodlar) bilan kirishga yo'l qo'yish. JavaScript'da buning eng kuchli vositasi — #.
2. Eski yo'l: _ konventsiyasi
# paydo bo'lishidan oldin dasturchilar kelishib olgan edi: "nomi _ bilan boshlangan xususiyatga tashqaridan tegmang". Bunday kelishuv konventsiya (convention) deyiladi — til majburlamaydi, odamlar o'zaro shunday kelishgan. Yo'l harakatidagi "o'ng tomondan yuring" odatiga o'xshaydi: tartibni saqlaydi, lekin buzganni hech narsa to'xtatmaydi.
class Kassa {
_tushum = 0;
sotish(summa) {
if (summa > 0) {
this._tushum += summa;
}
}
}
const kassa = new Kassa();
kassa._tushum = 1000000;
console.log(kassa._tushum); // 1000000_ — faqat iltimos. JavaScript uchun _tushum — boshqa har qanday nom kabi oddiy xususiyat. Kelishuvni bilgan va hurmat qilgan odam unga tegmaydi; bilmagan yoki shoshilgan odam — tegadi. Eski kutubxonalarda _ bilan boshlangan nomlarni hali ko'p uchratasiz.
Haqiqiy yashirishning yana bir eski yo'li bor edi — closure. Klass o'rniga funksiya obyekt qaytaradi, ma'lumot esa funksiyaning ichki o'zgaruvchisida qoladi:
function kassaYarat() {
let tushum = 0;
return {
sotish(summa) {
if (summa > 0) {
tushum += summa;
}
},
jaminiAyt() {
return tushum;
},
};
}
const kassa = kassaYarat();
kassa.sotish(35000);
console.log(kassa.jaminiAyt(), kassa.tushum); // 35000 undefinedBu ishonchli: tushum ga tashqaridan yo'l yo'q. Lekin har kassa o'z metodlarining nusxasini oladi (prototip yo'q), instanceof ham ishlamaydi. # ikkala dunyoning yaxshisini birlashtiradi: closure kabi yopiq, klass kabi metodlari prototipda.
3. # — haqiqiy private maydon
3.1 Birinchi private maydon
class Kassa {
#tushum = 0;
sotish(summa) {
if (summa > 0) {
this.#tushum += summa;
}
}
jaminiAyt() {
return `Bugungi tushum: ${this.#tushum} so'm`;
}
}
const kassa = new Kassa();
kassa.sotish(35000);
kassa.sotish(28000);
console.log(kassa.jaminiAyt()); // Bugungi tushum: 63000 so'm
console.log(kassa.tushum); // undefined
console.log(Object.keys(kassa)); // []
console.log(JSON.stringify(kassa)); // {}Qoidalar:
- E'lon — klass tanasida.
#tushum = 0;— maydon kabi, faqat nom oldida#. Qiymatsiz ham bo'ladi:#tushum;. - Murojaat —
this.#tushum.#nomning bir qismi:#tushumvatushum— butunlay boshqa-boshqa narsa. Shuning uchunkassa.tushum—undefined. - Tashqaridan ko'rinmaydi.
Object.keys,for...in,JSON.stringify, spread ({ ...kassa }),structuredClone— hech biri private maydonni olmaydi.
Private maydon (private field) — nomi # bilan boshlangan, faqat o'z klassi ichidan o'qiladigan va yoziladigan maydon.
Diagrammada kim qayerga yeta olishini ko'ring. Chegara — klass bloki: ichidagi metodlar #tushum ga to'g'ridan-to'g'ri boradi, tashqi kod esa faqat ochiq metodlar orqali:
flowchart LR
subgraph K["class Kassa"]
S["sotish()"] --> T["#tushum"]
J["jaminiAyt()"] --> T
end
X["Tashqi kod"] --> S
X --> J
X -. "SyntaxError" .-x TUzluksiz o'qlar — ruxsat berilgan yo'llar, uzuq chiziq — taqiqlangan. Tashqi kod tushumni ko'ra oladi va oshira oladi, lekin faqat klass bergan ikki "eshik" orqali. Yangi eshik kerak bo'lsa — uni klass muallifi qo'shadi, tashqaridagi kod emas.
3.2 Tashqaridan kirishga urinish
class Kassa {
#tushum = 0;
}
const kassa = new Kassa();
kassa.#tushum = 1000000;SyntaxError: Private field '#tushum' must be declared in an enclosing classTarjimasi: "#tushum private maydoni uni o'rab turgan klassda e'lon qilingan bo'lishi kerak". E'tibor bering — bu TypeError emas, SyntaxError. JavaScript faylni ishga tushirishdan oldin, o'qish bosqichidayoq to'xtatadi. Klass tashqarisida #tushum yozilgan har qanday qator — butun faylni ishlatmaydi. Bu himoyani aylanib o'tib bo'lmaydi: maxsus "kalit" ham, hiyla ham yo'q.
Qavsli yozuv ham yordam bermaydi: kassa["#tushum"] = 1 xatosiz ishlaydi, lekin u "#tushum" nomli oddiy xususiyat yaratadi. Private maydon o'zgarmay qoladi.
3.3 Konsolda ko'rinishi
Node private maydonni ko'rsatmaydi: console.log(kassa) — Kassa {}. Chrome DevTools konsoli esa ko'rsatadi: Kassa {#tushum: 63000}. Bu xato emas — DevTools dasturchiga yordam beradigan maxsus vosita, u kodga ruxsat bermaydi. Sahifadagi skriptlar baribir #tushum ga yeta olmaydi. Ma'nosi bir xil: maydon bor, lekin tashqi kod uchun yopiq.
Tekshirib ko'ring:
kassa["#tushum"] = 5dan keyinkassa.jaminiAyt()nimani ko'rsatadi?
Javob
Avvalgi tushumni — o'zgarmaydi. kassa["#tushum"] — satr kalitli oddiy xususiyat, u this.#tushum bilan hech qanday bog'liq emas. Object.keys(kassa) endi [ '#tushum' ] ko'rsatadi — bu chalkash ko'rinadi, lekin private maydon joyida.
4. Getter: o'qishga ruxsat, yozishga — yo'q
Kassa ekranida jami ko'rinib turishi kerak. Har safar jaminiAyt() deb metod chaqirish o'rniga — getter. Uni Getter va setter darsida obyekt literalida ko'rgansiz; klassda ham xuddi shunday yoziladi (klassdagi getter, setter va static ni keyingi darsda to'liq o'rganamiz):
class Kassa {
#tushum = 0;
sotish(summa) {
if (summa > 0) {
this.#tushum += summa;
}
}
get tushum() {
return this.#tushum;
}
}
const kassa = new Kassa();
kassa.sotish(35000);
console.log(kassa.tushum); // 35000Endi kassa.tushum o'qiladi — xuddi oddiy xususiyatdek, qavssiz. Lekin setter yo'q, demak yozib bo'lmaydi. Yozishga urinish nima beradi — fayl turiga bog'liq (Strict mode):
class Kassa {
#tushum = 0;
get tushum() {
return this.#tushum;
}
}
const kassa = new Kassa();
kassa.tushum = 1000000;TypeError: Cannot set property tushum of #<Kassa> which has only a getterTarjimasi: "Kassa nusxasining tushum xususiyatini o'rnatib bo'lmaydi — unda faqat getter bor". Modul faylda va "use strict" da shunday aniq xato chiqadi — saytdagi «Ishga tushir» tugmasi ham kodni strict rejimda bajaradi. Oddiy, strict bo'lmagan <script> da esa tayinlash jimgina e'tiborsiz qoldiriladi — tushum o'zgarmaydi, lekin xato ham chiqmaydi. vazifalar.js esa strict — darsning «Vazifalar qadami» da aynan shu TypeError ni o'z ko'zingiz bilan ko'rasiz.
Private maydon + getter — eng ko'p uchraydigan juftlik: "hamma o'qiy oladi, faqat klass o'zgartiradi".
Getter nomi va private maydon nomi bir xil bo'lishi (tushum va #tushum) — odatiy va xavfsiz: # nomning bir qismi bo'lgani uchun ular to'qnashmaydi. Tashqi kod kassa.tushum ni ko'radi va uning ortida nima turganini bilishi shart emas. Ertaga tushumni boshqacha saqlashga qaror qilsangiz (masalan, har sotuvni ro'yxatga yozib, jamini getter'da hisoblash), tashqi kod o'zgarmaydi — kassa.tushum avvalgidek ishlaydi.
Tekshirib ko'ring:
get tushum()olib tashlansa,kassa.tushumnima qaytaradi? Xato chiqadimi?
Javob
undefined, xatosiz. tushum nomli oddiy xususiyat ham, getter ham yo'q — oddiy "topilmadi" holati. Private #tushum bilan bu nom hech qanday bog'liq emas.
5. Private metodlar
Metod ham private bo'lishi mumkin — klassning ichki yordamchisi. «Bahor» kassasi summani tekshirish qoidasini kengaytirdi: butun son, musbat va bir chekda 10 million so'mdan oshmasin:
class Kassa {
#tushum = 0;
sotish(summa) {
if (!this.#togrimi(summa)) {
return false;
}
this.#tushum += summa;
return true;
}
get tushum() {
return this.#tushum;
}
#togrimi(summa) {
return Number.isInteger(summa) && summa > 0 && summa <= 10000000;
}
}
const kassa = new Kassa();
console.log(kassa.sotish(35000)); // true
console.log(kassa.sotish(-5000)); // false
console.log(kassa.sotish(2.5)); // false
console.log(kassa.tushum); // 35000kassa.sotish(-5000) qanday yo'ldan o'tishini Keyingi tugmasi bilan kuzating:
#togrimi — predikat ("-mi" bilan), faqat klass ichida chaqiriladi: this.#togrimi(summa). Tashqaridan kassa.#togrimi(5) — xuddi maydondagidek SyntaxError. sotish endi natijani qaytaradi: true — qabul qilindi, false — rad etildi. Chaqirgan kod qaror qabul qila oladi.
Nega yordamchini private qilish kerak? Ochiq metod — va'da. Uni bir marta tashqariga chiqarsangiz, boshqa kod unga tayanib qoladi va keyin nomini yoki xulqini o'zgartira olmaysiz. Private metodni esa xohlagancha o'zgartirasiz — uni faqat klass ichidagi kod biladi. Ochiq qism kichik, ichki qism erkin — yaxshi klassning belgisi.
Tekshirib ko'ring: Tekshiruvni to'g'ridan-to'g'ri
sotishichiga yozish ham mumkin edi. Nega alohida#togrimimetodi yaxshiroq?
Javob
Qoida bitta joyda va nomi bor: #togrimi o'qiganda "summa to'g'rimi?" degan savol darhol tushuniladi. Ertaga qaytarish (qaytarish(summa)) metodi qo'shilsa, u ham xuddi shu tekshiruvni chaqiradi — qoida ikki joyda takrorlanmaydi. Private bo'lgani uchun esa bu ichki tafsilot tashqariga "va'da" bo'lib chiqmaydi.
6. Private — klassga tegishli, nusxaga emas
6.1 Boshqa nusxaning private maydoni
Private maydonga "faqat o'z nusxasi" emas, o'sha klassning istalgan kodi kira oladi — boshqa nusxaniki ham:
class Kassa {
#tushum = 0;
constructor(boshlangich) {
this.#tushum = boshlangich;
}
kopmi(boshqa) {
return this.#tushum > boshqa.#tushum;
}
}
const chilonzor = new Kassa(450000);
const yunusobod = new Kassa(380000);
console.log(chilonzor.kopmi(yunusobod)); // truekopmi ichida boshqa.#tushum — boshqa nusxaning private maydoni. Ruxsat bor, chunki kod Kassa klassi ichida yozilgan. Chegara — klass matni: ichida — hamma narsa, tashqarisida — hech narsa.
6.2 Begona obyekt va brand check
kopmi ga Kassa bo'lmagan obyekt berilsa-chi?
class Kassa {
#tushum = 0;
kopmi(boshqa) {
return this.#tushum > boshqa.#tushum;
}
}
new Kassa().kopmi({ tushum: 0 });TypeError: Cannot read private member #tushum from an object whose class did not declare itTarjimasi: "#tushum private a'zosini uni e'lon qilmagan klassdan yaratilgan obyektdan o'qib bo'lmaydi". { tushum: 0 } — oddiy obyekt, unda #tushum yo'q.
Xatosiz tekshirish uchun maxsus operator bor — #maydon in obyekt. U true yoki false qaytaradi va hech qachon xato tashlamaydi. Private nom kabi, u ham faqat klass ichida yoziladi — tashqarida #tushum in kassa deb yozsangiz, «Tashqaridan kirishga urinish» bo'limidagi SyntaxError chiqadi. Shuning uchun tekshiruvni klass metodiga joylaymiz:
class Kassa {
#tushum = 0;
haqiqiymi(obyekt) {
return #tushum in obyekt;
}
}
const kassa = new Kassa();
const soxta = Object.create(Kassa.prototype);
console.log(soxta instanceof Kassa); // true
console.log(kassa.haqiqiymi(soxta)); // false
console.log(kassa.haqiqiymi(new Kassa())); // trueBrand check (inglizcha "tamg'a tekshiruvi") — obyekt haqiqatan shu klassning new i bilan yaratilganini tekshirish. Mollarga qo'yiladigan tamg'a kabi: uni faqat ishlab chiqaruvchi qo'ya oladi.
Farqqa qarang. soxta — Object.create(Kassa.prototype) bilan yasalgan, new siz. Uning prototipi to'g'ri, shuning uchun instanceof "ha" deydi (Object.create va instanceof darsida instanceof ni aldash mumkin degan edik). Lekin private maydon faqat new bilan, klassning o'zi tomonidan qo'yiladi — soxta da u yo'q. #tushum in aldanmaydi.
Bu operator 2021-yildan beri brauzerlarda bor (Baseline ma'lumoti: Baseline 2021-09, keng qo'llab-quvvatlanadi 2024-03 dan).
7. _ va #: qachon qaysi biri
_tushum |
#tushum |
|
|---|---|---|
| Tashqaridan o'qish/yozish | mumkin (kelishuv bilan "mumkin emas") | SyntaxError |
Object.keys, JSON, spread |
ko'rinadi | ko'rinmaydi |
| Klass ichidan | this._tushum |
this.#tushum |
| Qayerda ko'p | eski kod, ba'zi kutubxonalar | zamonaviy kod |
TypeScript'da yana bir variant bor — private tushum kalit so'zi. U faqat kod yozish paytida tekshiriladi, ishga tushgan JavaScript'da esa oddiy xususiyatga aylanadi. TypeScript'ni 15-qismda o'rganamiz, hozir bilish shart emas — faqat "private so'zi va # bir xil narsa emas" deb eslab qoling.
Private maydonlar haqida yana ikki fakt: ular ES2022 da tilga kirgan (Baseline ma'lumoti: private maydonlar Baseline 2021-07, keng qo'llab-quvvatlanadi 2024-01 dan; private metodlar — 2021-09 / 2024-03) va ularni delete bilan o'chirib bo'lmaydi (SyntaxError: Private fields can not be deleted).
7.1 Hammasini private qilish kerakmi?
Yo'q. Private — vosita, maqsad emas. Uchta savol yordam beradi:
- Noto'g'ri qiymat biror narsani buzadimi? Tushum manfiy bo'lib qolsa — hisobot yolg'on. Ha — private + tekshiruvchi metod.
- Qiymat boshqa qiymatlarga bog'liqmi? Masalan,
jami—narx × sonidan hisoblanadi. Uni tashqaridan yozib bo'lmasin — aks holdanarxbilan mos kelmay qoladi. Ko'pincha bunday qiymatni umuman saqlamay, getter bilan hisoblash yaxshiroq. - Qiymat har qanday bo'lishi mumkinmi? Vazifaning
bajarildiholati —trueyokifalse, ikkalasi ham to'g'ri. Uni ochiq qoldirish mumkin; ko'p jamoalar baribir o'zgartirishni metod orqali (almashtir()) qiladi, lekin buni majburlamaydi.
Haddan tashqari ko'p private maydon klassni sinashni va kengaytirishni qiyinlashtiradi. Bitta muhim fakt: klassdan meros olgan bola klass (Meros: extends va super) ham ota klassning # maydonlariga kira olmaydi — ular faqat o'sha klass matniga tegishli. Bolaga kerak bo'ladigan narsa uchun ota klass ochiq metod yoki getter beradi.
Tekshirib ko'ring:
Taomklassidanom,narxvasotilganSonibor. Qaysi birini private qilardingiz va nega?
Javob
Eng muhim nomzod — sotilganSoni: u faqat sotuvda bittaga oshishi kerak, uni tashqaridan "to'g'rilab" qo'yish statistikani buzadi. narx — ehtimol private + tekshiruvchi metod (narxniOzgartir), chunki manfiy yoki kasr narx xato. nom esa ochiq qolishi mumkin. Javob loyihaga bog'liq — asosiysi, har qaror "noto'g'ri qiymat nimani buzadi?" degan savoldan kelib chiqsin.
8. Ko'p uchraydigan xatolar
8.1 E'lon qilinmagan private maydon
class Kassa {
sotish(summa) {
this.#tushum += summa;
}
}SyntaxError: Private field '#tushum' must be declared in an enclosing classOddiy maydondan farqi: oddiy xususiyatni this.x = ... bilan istalgan joyda "yaratib" yuborsa bo'ladi, private maydonni esa — yo'q. U albatta klass tanasida e'lon qilinadi. Tuzatish: klass tepasiga #tushum = 0;.
8.2 Private maydon JSON'da yo'qoladi
JSON.stringify(kassa) — {}. Saqlash yoki serverga yuborish kerak bo'lsa, bu ma'lumot yo'qolishi. Tuzatish: klassga toJSON() metodi (JSON chuqur) — u JSON'ga nima tushishini o'zi aytadi:
class Kassa {
#tushum = 63000;
toJSON() {
return { tushum: this.#tushum };
}
}
console.log(JSON.stringify(new Kassa())); // {"tushum":63000}structuredClone va spread uchun bunday ilgak yo'q — ular private maydonsiz oddiy obyekt beradi.
8.3 Getter bor, metod yo'q — jim tayinlash
Oddiy <script> da kassa.tushum = 0 hech narsa qilmaydi va xato ham bermaydi. Kod "ishladi" deb o'ylaysiz, aslida qiymat o'zgarmadi. Tuzatish: o'zgartirish uchun maxsus metod (sotish, matnniOzgartir) chaqiring; xatolarni ko'rish uchun kodni modulga yoki strict rejimga o'tkazing.
8.4 kassa["#tushum"] — boshqa xususiyat
«Tashqaridan kirishga urinish» bo'limidagi kabi: satr kalit private maydonga yetmaydi, yangi oddiy xususiyat yaratadi.
9. Mashqlar
1-mashq (oson): Hisoblagich
Navbat klassini yozing: private #raqam = 0, keyingisi() metodi raqamni bittaga oshirib qaytarsin, joriy getter'i joriy raqamni bersin. Tashqaridan raqamni o'zgartirib bo'lmasligini ko'rsating (Object.keys bilan).
Yechim
class Navbat {
#raqam = 0;
keyingisi() {
this.#raqam++;
return this.#raqam;
}
get joriy() {
return this.#raqam;
}
}
const navbat = new Navbat();
navbat.keyingisi();
navbat.keyingisi();
console.log(navbat.joriy); // 2
console.log(Object.keys(navbat)); // []Raqamni faqat keyingisi o'zgartiradi — orqaga qaytarish yoki sakrash imkoni yo'q.
2-mashq (o'rta): _ dan # ga
Quyidagi klassni # ga o'tkazing. _balans ga tashqaridan yetib bo'lmasin, lekin balansni o'qish mumkin bo'lsin.
class Hamyon {
_balans = 0;
toldir(summa) {
if (summa > 0) {
this._balans += summa;
}
}
}Yechim
class Hamyon {
#balans = 0;
toldir(summa) {
if (summa > 0) {
this.#balans += summa;
}
}
get balans() {
return this.#balans;
}
}
const hamyon = new Hamyon();
hamyon.toldir(50000);
console.log(hamyon.balans); // 50000
console.log(JSON.stringify(hamyon)); // {}Uchta o'zgarish: e'londa _ → #, ichida this._balans → this.#balans, va o'qish uchun getter. JSON.stringify endi bo'sh — kerak bo'lsa, toJSON() qo'shing.
3-mashq (qiyin): Tamg'ali taqqoslash
Stol klassi: private #raqam (konstruktorda beriladi), raqam getter'i, va tengmi(boshqa) metodi — boshqa haqiqiy Stol bo'lmasa false, bo'lsa raqamlarni solishtirsin. { raqam: 5 } va Object.create(Stol.prototype) bilan sinang.
Yechim
class Stol {
#raqam;
constructor(raqam) {
this.#raqam = raqam;
}
get raqam() {
return this.#raqam;
}
tengmi(boshqa) {
return #raqam in boshqa && this.#raqam === boshqa.#raqam;
}
}
const stol = new Stol(5);
console.log(stol.tengmi(new Stol(5))); // true
console.log(stol.tengmi({ raqam: 5 })); // false
console.log(stol.tengmi(Object.create(Stol.prototype))); // false&& qisqa tutashuvi (Mantiqiy operatorlar) muhim: brand check false bersa, boshqa.#raqam umuman o'qilmaydi — TypeError chiqmaydi. { raqam: 5 } ning raqam i bor, lekin tamg'asi yo'q.
4-mashq: Vazifalar qadami — #matn va branch'ni yakunlash
refactor/vazifa-klassi dagi oxirgi qadam. Hozir istalgan kod vazifa matnini to'g'ridan-to'g'ri yozishi mumkin: vazifa.matn = "". Forma xatoniTop bilan bo'sh matnni to'xtatadi, lekin bu tekshiruv Vazifa ning o'zida emas.
matnni private#matnga aylantiring va o'qish uchunmatngetter'ini qo'shing.- O'zgartirish uchun
matnniOzgartir(yangi)metodini yozing: bo'sh joylarni olib tashlasin; bo'sh yoki 100 belgidan uzun bo'lsa —falseqaytarib, hech narsani o'zgartirmasin; aks holda matnni yozib,trueqaytarsin. - Faqat klassni o'zgartirib, sahifani oching va vazifani tahrirlab ko'ring. Nima bo'ldi?
- Muammoni tuzating.
JSON.stringify(holat.vazifalar)natijasi avvalgidek qolishini ham ta'minlang.
Yechim
1–2-qadamdan keyin Vazifa:
class Vazifa {
id;
bajarildi;
#matn;
constructor(id, matn, bajarildi = false) {
this.id = id;
this.#matn = matn;
this.bajarildi = bajarildi;
}
get matn() {
return this.#matn;
}
matnniOzgartir(yangi) {
const toza = yangi.trim();
if (toza === "" || toza.length > 100) {
return false;
}
this.#matn = toza;
return true;
}
toJSON() {
return {
id: this.id,
matn: this.#matn,
bajarildi: this.bajarildi,
};
}
almashtir() {
this.bajarildi = !this.bajarildi;
}
}3-qadam — xato. Sahifa ochiladi, ro'yxat, belgilash, qo'shish, o'chirish — hammasi ishlaydi. "DOM darsini takrorlash" ni tahrirlab, yangi matn yozib Enter bosing: qator tahrir rejimida qolib ketadi, "O'zgarish saqlandi." e'loni chiqmaydi. Konsolda:
Uncaught TypeError: Cannot set property matn of #<Vazifa> which has only a getterSabab — class sintaksisi darsida yozilgan matnniAlmashtir:
function matnniAlmashtir(id, matn) {
vazifaniTop(id).matn = matn; // getter'li xususiyatga yozish
holat.tahrirId = null;
render();
}matn endi faqat getter. vazifalar.js ning boshida "use strict" bor (Strict mode), shuning uchun getter'li xususiyatga yozish — TypeError («Getter» bo'limidagi qoida). Xato funksiyaning birinchi qatorida chiqdi: undan keyingi hamma narsa — tahrirId = null, render(), fokus va e'lon — bajarilmay qoldi. Strict bo'lmagan skriptda esa tayinlash jimgina e'tiborsiz qolardi: "O'zgarish saqlandi." deb e'lon qilinardi, qatorda esa eski matn turardi. Baland xato bitta qatorni ko'rsatadi, jim xatoni esa uzoq qidirish kerak bo'lardi — qat'iy rejimni yoqqanimizning foydasi shu.
4-qadam — tuzatish. Bitta qator:
function matnniAlmashtir(id, matn) {
vazifaniTop(id).matnniOzgartir(matn);
holat.tahrirId = null;
render();
}Qolgan kod tegilmadi: vazifa.matn ni o'qiydigan joylar (oddiyQator, tahrirQatori, xatoniTop, o'chirish e'loni) getter orqali ishlaydi.
toJSON nega kerak? Usiz JSON.stringify(holat.vazifalar) har vazifada matn siz {"id":1,"bajarildi":false} beradi — private maydon JSON'ga tushmaydi («Private maydon JSON'da yo'qoladi»). Eksport tugmasi (JSON asoslari) aynan JSON.stringify bilan ishlaydi: toJSON siz eksportdagi har vazifa matnsiz chiqardi, 11-qismdagi saqlash ham matnlarni jimgina yo'qotardi. toJSON bilan natija refaktoringdan oldingi bilan harfma-harf bir xil.
Xulq o'zgarmaganini tekshiring — bu uch darsdagi refaktoringning yakuniy sinovi:
- Ochilganda — uch vazifa, "2 ta vazifa qoldi, 1 ta bajarildi", konsolda xato yo'q.
- Tahrirlash → yangi matn →
Enter: matn yangilandi, "O'zgarish saqlandi.", fokus «Tahrirlash» tugmasida. - Tahrirda boshqa vazifaning matnini yozsangiz — "Bu vazifa ro'yxatda allaqachon bor."; bo'sh qoldirib «Saqlash» — "Vazifa matnini yozing.".
Esc— o'zgarishsiz qaytadi. - Belgilash, «Faol»/«Bajarilgan», o'chirish va bo'sh holat — 09-qismdagidek.
- Konsolda
JSON.stringify(holat.vazifalar)— har vazifadaid,matn,bajarildi; eksport matni ham avvalgidek.
| Dars | Vazifa ga nima qo'shildi |
|---|---|
class sintaksisi |
klass, constructor, almashtir() |
| Class maydonlari | maydonlar ro'yxati (id; matn; bajarildi;) |
| shu dars | #matn, matn getter, matnniOzgartir, toJSON |
Commit va branch'ni yakunlash:
git add assets/js/vazifalar.js
git commit -m "Vazifalar: vazifa matnini private qil"
git switch main
git merge refactor/vazifa-klassi
git branch -d refactor/vazifa-klassi
git pushBir-ikki daqiqadan keyin Pages'dagi saytni telefonda oching: foydalanuvchi hech narsa sezmasligi kerak. Keyingi modulda butun ro'yxat ham klassga aylanadi — VazifalarRoyxati.
10. Real ishda
- Kutubxonalar va SDK'lar. Zamonaviy kutubxonalar ichki holatni
#bilan yashiradi — foydalanuvchi faqat hujjatlashtirilgan metodlarni ishlatadi, mualliflar esa ichki qismni bemalol qayta yozadi. - To'lov va pul. Click/Payme bilan ishlaydigan kodda balans, tranzaksiya holati kabi qiymatlar faqat metod orqali o'zgarishi kerak — private maydon + getter + tekshiruvchi metod aynan shu qolip.
- Brand check — DOM ichida ham bor: brauzer
Element.prototypemetodini element bo'lmagan obyekt bilan chaqirsangiz,TypeError: Illegal invocationberadi. O'z klasslaringizda#x in objxuddi shunday himoya. - Intervyu. "
#va_farqi?", "Private maydonJSON.stringifyda ko'rinadimi?", "TypeScriptprivateva#farqi?" — klasslar bo'yicha tez-tez beriladigan savollar.
Xulosa
#maydonva#metod()— faqat o'z klassi ichidan ko'rinadi; tashqarida#yozish —SyntaxError, fayl umuman ishlamaydi.- Private maydon
Object.keys, JSON, spread vastructuredCloneda ko'rinmaydi; JSON kerak bo'lsa —toJSON(). - Getter — "o'qish mumkin, yozish yo'q": strict rejimda yozish
TypeError, oddiy skriptda — jim e'tiborsiz. - Private — klassga tegishli: klass kodi boshqa nusxaning
#maydoniga ham kira oladi. #maydon in obj— aldab bo'lmaydigan brand check;instanceofni esaObject.createaldaydi._— faqat kelishuv; zamonaviy kodda haqiqiy yashirish uchun#.
Keyingi dars: Getter/setter va static a'zolar — klassdagi getter va setter'ni to'liq ko'ramiz va nusxaga emas, klassning o'ziga tegishli static maydon va metodlarni o'rganamiz.
Manbalar
- MDN: "Private elements", "in operator" (private names), "Classes" — developer.mozilla.org
- ECMAScript 2025 Language Specification: "PrivateFieldGet", "PrivateElementFind" — tc39.es/ecma262
- web-features:
javascript.classes.private_class_fields,private_class_methods,private_class_fields_in
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!