Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. Deskriptorni ko'rish
- 2.1 Object.getOwnPropertyDescriptor
- 2.2 Sirlarning javobi
- 3. Object.defineProperty
- 3.1 Bayroqlarni o'zimiz qo'yamiz
- 3.2 Tuzoq: yozilmagan bayroq — false
- 4. Uch bayroq yaqindan
- 4.1 writable: false — faqat o'qiladi
- 4.2 enumerable: false — "sanalmaydi"
- 4.3 configurable: false — "bir tomonlama eshik"
- 5. Accessor deskriptor: getter va setter
- 5.1 Ikki xil deskriptor
- 5.2 Mavjud obyektga getter qo'shish
- 6. Ko'p xususiyat bilan ishlash
- 6.1 Ko'plik shakllari
- 6.2 Getter'ni "tirik" holda nusxalash
- 7. Ko'p uchraydigan xatolar
- 7.1 defineProperty dan keyin xususiyat "yo'qoldi"
- 7.2 Faqat o'qiladigan xususiyat jim o'zgarmaydi
- 7.3 Cannot redefine property
- 7.4 value va get birga
- 7.5 Arrow funksiya getter sifatida
- 8. Mashqlar
- 1-mashq (oson): Deskriptorlarni o'qing
- 2-mashq (o'rta): O'zgarmas buyurtma raqami
- 3-mashq (qiyin): To'liq nusxa funksiyasi
- 4-mashq: Vazifalar qadami — qoldi ma'lumot emas
- 9. Real ishda
- Xulosa
- Manbalar
JavaScript xususiyat deskriptorlari: writable, enumerable, configurable va Object.defineProperty
Qisqacha: Obyektning har bir xususiyatida qiymatdan tashqari uchta yashirin ruxsat bor:
writable(o'zgartirsa bo'ladimi),enumerable(Object.keysva spread'da ko'rinadimi) vaconfigurable(o'chirsa yoki qayta sozlasa bo'ladimi). UlarniObject.getOwnPropertyDescriptorko'rsatadi,Object.definePropertyesa o'rnatadi. Diqqat:definePropertyda yozilmagan ruxsat —false.
Bu darsda
- Xususiyatning deskriptorini o'qiy olasiz va undagi to'rt maydonni tushuntira olasiz.
Object.definePropertybilan faqat o'qiladigan, yashirin yoki o'chirib bo'lmaydigan xususiyat yasay olasiz.- Nega
Object.keys([1, 2])dalengthyo'qligini vaMath.PI = 3nega ishlamasligini tushuntira olasiz. - Ma'lumot deskriptori va accessor (getter/setter) deskriptori farqini bilasiz.
- Getter'ni "qotirmasdan" nusxalay olasiz va
vazifalardagiqoldini nusxalardan yashirasiz.
Oldin bilishingiz kerak: Getter va setter, Obyekt bo'ylab yurish, Obyekt: kalit-qiymat juftliklari, Sayoz va chuqur nusxalash.
1. Nega bu kerak?
Uchta kichik sirli holat:
const narxlar = [35000, 28000];
console.log(Object.keys(narxlar)); // [ '0', '1' ]
console.log(narxlar.length); // 2Massivda length xususiyati bor — o'qisa bo'ladi. Lekin Object.keys uni ko'rsatmadi. Nega?
Math.PI = 3;
console.log(Math.PI); // 3.141592653589793Math.PI ga 3 yozdik — xato ham chiqmadi, o'zgarmadi ham. Nega?
Uchinchisi — oldingi darsdan. Getter va setter darsida spread getter'ni "qotirib" qo'ydi: { ...savat } da jami oddiy songa aylandi. Getter'ni getter holida nusxalashning yo'li bormi?
Uchala savolning javobi bitta: har xususiyatning yashirin sozlamalari bor. Obyekt literalida ular ko'rinmaydi, lekin JavaScript ularga doim qaraydi.
Hayotdan o'xshatish: Telegram guruhidagi a'zo. Ro'yxatda faqat ismi ko'rinadi. Lekin admin panelida har a'zo uchun alohida tugmalar bor: "xabar yoza oladimi?", "a'zolar ro'yxatida ko'rinadimi?", "uning ruxsatlarini keyin o'zgartirsa bo'ladimi?". Oddiy foydalanuvchi bu tugmalarni ko'rmaydi, lekin guruh aynan ular bo'yicha ishlaydi. Xususiyat deskriptori — o'sha admin paneli.
2. Deskriptorni ko'rish
2.1 Object.getOwnPropertyDescriptor
const taom = { nom: "Osh", narx: 35000 };
console.log(Object.getOwnPropertyDescriptor(taom, "narx"));Konsolda:
{ value: 35000, writable: true, enumerable: true, configurable: true }Xususiyat deskriptori (property descriptor) — xususiyatning to'liq tavsifi: qiymati va uchta ruxsat bayrog'i. "Descriptor" — inglizcha "tavsiflovchi". Nomi uzun, lekin o'qilishi oddiy: "obyektning o'z (own) xususiyatining tavsifini ber". Own — Obyekt bo'ylab yurish darsidagi ma'no: meros emas, obyektning o'zida turgan xususiyat.
To'rt maydon:
| Maydon | Savol | false bo'lsa |
|---|---|---|
value |
qiymati nima? | — |
writable |
qiymatini o'zgartirsa bo'ladimi? | yozish rad etiladi |
enumerable |
sanab chiqishda ko'rinadimi? | Object.keys, spread, for...in uni ko'rmaydi |
configurable |
o'chirsa va qayta sozlasa bo'ladimi? | delete va qayta sozlash rad etiladi |
Literal ({ ... }) yoki oddiy tayinlash (taom.narx = ...) bilan yaratilgan xususiyatda uchala bayroq — true. Shuning uchun biz hozirgacha ularni sezmadik: hamma narsa ruxsat etilgan edi.
2.2 Sirlarning javobi
Endi «Nega bu kerak?» bo'limidagi ikki holatning deskriptoriga qaraymiz:
const narxlar = [35000, 28000];
console.log(Object.getOwnPropertyDescriptor(narxlar, "length"));
console.log(Object.getOwnPropertyDescriptor(Math, "PI"));Konsolda:
{ value: 2, writable: true, enumerable: false, configurable: false }
{
value: 3.141592653589793,
writable: false,
enumerable: false,
configurable: false
}Massivning length i — enumerable: false. Shuning uchun Object.keys uni ko'rmaydi, lekin o'qish va yozish mumkin (writable: true — teshikli massivlar darsida length ga yozgan edik). Math.PI esa — uchala bayroq false: o'zgartirib ham, o'chirib ham, sanab ham bo'lmaydi. Pi soni 3 ga aylanib qolmasligi kerak.
Node bu deskriptorni bir necha qatorga bo'lib chiqardi — qator uzun bo'lgani uchun. Ma'nosi bir xil.
Tekshirib ko'ring:
Object.getOwnPropertyDescriptor("osh", "length")nima qaytaradi deb o'ylaysiz?writableqanday bo'ladi?
Javob
{ value: 3, writable: false, enumerable: false, configurable: false }. Satr o'zgarmas (String asoslari) — uning uzunligini ham o'zgartirib bo'lmaydi. Shuning uchun writable: false.
3. Object.defineProperty
3.1 Bayroqlarni o'zimiz qo'yamiz
Object.defineProperty(obyekt, "kalit", deskriptor) — xususiyatni kerakli bayroqlar bilan yaratadi yoki o'zgartiradi:
const buyurtma = { taom: "Osh" };
Object.defineProperty(buyurtma, "id", {
value: 17,
writable: false,
enumerable: true,
configurable: false,
});
console.log(buyurtma); // { taom: 'Osh', id: 17 }id — buyurtmaning raqami. U bir marta beriladi va hech qachon o'zgarmasligi kerak: o'zgarsa, oshxonadagi chek boshqa buyurtmaga tegishli bo'lib qoladi. writable: false va configurable: false — aynan shu kafolat.
3.2 Tuzoq: yozilmagan bayroq — false
Endi xuddi shu ishni qisqaroq yozamiz — faqat value bilan:
const buyurtma = { taom: "Osh" };
Object.defineProperty(buyurtma, "id", { value: 17 });
console.log(buyurtma); // { taom: 'Osh' }
console.log(buyurtma.id); // 17
console.log(Object.getOwnPropertyDescriptor(buyurtma, "id"));Konsolda:
{ taom: 'Osh' }
17
{ value: 17, writable: false, enumerable: false, configurable: false }id bor (buyurtma.id — 17), lekin konsolda ko'rinmaydi! Sababi — sukut bo'yicha qiymatlar:
| Qanday yaratildi | writable |
enumerable |
configurable |
|---|---|---|---|
Literal yoki obj.x = 1 |
true |
true |
true |
Object.defineProperty |
false |
false |
false |
defineProperty "qat'iy" tomondan boshlaydi: siz aniq ruxsat bermagan narsa — taqiqlangan. Node konsoli sanalmaydigan (enumerable: false) xususiyatni ko'rsatmaydi, shuning uchun id "yo'qoldi". Bu — defineProperty bilan ishlashdagi eng ko'p uchraydigan hayrat.
Diqqat:
definePropertyda faqat bitta bayroqni o'zgartirmoqchi bo'lsangiz va xususiyat allaqachon bor bo'lsa — qolganlari o'zgarmaydi. Sukut bo'yichafalsefaqat yangi xususiyat yaratilganda ishlaydi. Shuning uchunObject.defineProperty(obj, "x", { enumerable: false })mavjudxni faqat yashiradi — qiymatiga tegmaydi.
Tekshirib ko'ring:
const menyu = { osh: 35000 };dan keyinObject.defineProperty(menyu, "osh", { value: 40000 }).Object.keys(menyu)nima qaytaradi?oshendi faqat o'qiladimi?
Javob
[ 'osh' ] — osh ko'rinib turibdi, qiymati 40000. Bayroqlari o'zgarmadi: uchalasi ham true qoldi, ya'ni yozsa ham bo'ladi. osh allaqachon bor edi — defineProperty faqat siz yozgan maydonni (value) almashtirdi. Sukut bo'yicha false faqat yangi xususiyatga tegishli.
4. Uch bayroq yaqindan
4.1 writable: false — faqat o'qiladi
const buyurtma = {};
Object.defineProperty(buyurtma, "id", {
value: 17,
enumerable: true,
});
buyurtma.id = 99;TypeError: Cannot assign to read only property 'id' of object '#<Object>'Tarjimasi: "obyektning faqat o'qiladigan id xususiyatiga qiymat berib bo'lmaydi". Bu — modul faylda (.mjs); shu sahifadagi «Ishga tushir» tugmasi ham qat'iy rejimda ishlaydi va xuddi shu xatoni ko'rsatadi. Oddiy skriptda esa — oldingi darsdagi getter kabi — yozish jimgina e'tiborsiz qoladi, Math.PI = 3 dagidek. Ikki rejim farqi — Strict mode darsida.
4.2 enumerable: false — "sanalmaydi"
Sanalmaydigan xususiyat bor, uni o'qish mumkin, lekin "hamma xususiyatlarni ber" degan vositalar uni o'tkazib yuboradi:
const taom = { nom: "Osh" };
Object.defineProperty(taom, "ichkiKod", {
value: "T-01",
writable: true,
});
console.log(taom.ichkiKod); // T-01
console.log(Object.keys(taom)); // [ 'nom' ]
console.log({ ...taom }); // { nom: 'Osh' }
console.log("ichkiKod" in taom); // true
console.log(Object.hasOwn(taom, "ichkiKod")); // trueObject.keys, Object.values, Object.entries, spread, for...in va Object.assign uni ko'rmaydi. in va Object.hasOwn esa ko'radi — ular "bormi?" deb so'raydi, "sanab ber" deb emas.
Qachon kerak? Obyektning "texnik" qismini ma'lumotdan ajratish uchun: ichki kod, hisoblanadigan qiymat, yordamchi metod. Ular foydalanuvchi ma'lumoti emas — nusxaga ham, ro'yxatga ham tushmasin.
Real misol. Jasur aka menyuga "eng arzon taom" metodini qo'shdi:
const menyu = {
osh: 35000,
lagmon: 28000,
manti: 30000,
arzoni() {
return Math.min(...Object.values(this));
},
};
const kalitlar = Object.keys(menyu);
console.log(kalitlar); // [ 'osh', 'lagmon', 'manti', 'arzoni' ]
console.log(menyu.arzoni()); // NaNNaN! Object.values(this) narxlar bilan birga metodning o'zini ham oldi — metod ham oddiy, sanaladigan xususiyat. Math.min funksiyani songa aylantira olmadi. Menyuni sahifaga chiqaradigan har qanday sikl ham "arzoni" degan g'alati taomni ko'rsatardi.
Metodni sanalmaydigan qilamiz:
const menyu = {
osh: 35000,
lagmon: 28000,
manti: 30000,
arzoni() {
return Math.min(...Object.values(this));
},
};
Object.defineProperty(menyu, "arzoni", { enumerable: false });
console.log(Object.keys(menyu)); // [ 'osh', 'lagmon', 'manti' ]
console.log(menyu.arzoni()); // 28000Endi menyu — faqat taomlar, metod esa joyida va ishlaydi. Albatta, yaxshiroq yechim ham bor: ma'lumot va amallarni bitta obyektga aralashtirmaslik (masalan, narxlarni menyu.narxlar ichida saqlash). Lekin tayyor obyekt bilan ishlayotganda enumerable: false — tez va aniq yo'l.
Qaysi vosita sanalmaydigan xususiyatni ko'radi — umumiy jadval:
| Vosita | Sanalmaydiganni ko'radimi? |
|---|---|
Object.keys, values, entries |
yo'q |
for...in, spread { ...o }, Object.assign |
yo'q |
obj.x, in, Object.hasOwn |
ha |
Object.getOwnPropertyNames, getOwnPropertyDescriptors |
ha |
Qoida: "sanab ber" degan vositalar — ko'rmaydi; "shu kalit bormi, uni ber" degan vositalar — ko'radi. Oxirgi qatordagi ikki metod "hammasini, yashirinlarini ham ber" deydi — ular Object.* metodlari darsida.
Tekshirib ko'ring: Sanalmaydigan
arzonimetodi bormenyuni{ ...menyu }bilan nusxaladingiz. Nusxadanusxa.arzoni()ishlaydimi?
Javob
Yo'q — TypeError: nusxa.arzoni is not a function. Spread faqat sanaladigan xususiyatlarni ko'chiradi, arzoni esa nusxaga tushmadi. Yashirish ham, nusxadan tushib qolish ham — bitta bayroqning ikki natijasi. Metod nusxada ham kerak bo'lsa, «Ko'p xususiyat bilan ishlash» bo'limidagi deskriptor nusxasi kerak.
Nega for...in massivda length ni bermasligi endi aniq:
for (const k in ["osh", "manti"]) {
console.log(k);
}Konsolda:
0
1Faqat indekslar — length sanalmaydi. JavaScript'ning o'rnatilgan metodlari (push, map, toString) ham sanalmaydigan qilib yaratilgan. Aks holda har for...in ularni ham chiqarardi (for...of va for...in).
4.3 configurable: false — "bir tomonlama eshik"
configurable: false xususiyatni o'chirishni va uning bayroqlarini o'zgartirishni taqiqlaydi:
const buyurtma = {};
Object.defineProperty(buyurtma, "id", {
value: 17,
enumerable: true,
});
Object.defineProperty(buyurtma, "id", { enumerable: false });TypeError: Cannot redefine property: idTarjimasi: "id xususiyatini qayta aniqlab bo'lmaydi". Bu xato modulda ham, oddiy skriptda ham bir xil chiqadi — defineProperty hech qachon jim rad etmaydi.
configurable: false — qaytarib bo'lmaydigan qaror. Uni true ga qaytarib ham bo'lmaydi. Yagona istisno: writable ni true dan false ga (faqat shu yo'nalishda) o'zgartirish mumkin — bu xususiyatni yanada qat'iyroq qiladi, bo'shatmaydi.
Hayotdan o'xshatish: pasportdagi tug'ilgan sana. Yozib qo'yilgan — o'zgartirib bo'lmaydi (writable: false), pasportdan o'chirib ham bo'lmaydi (configurable: false). Bu cheklovlarni olib tashlaydigan "admin" ham yo'q.
Tekshirib ko'ring:
const o = {}; Object.defineProperty(o, "x", { value: 1, writable: true });—o.x = 5ishlaydimi?delete o.xchi?Object.keys(o)nima qaytaradi?
Javob
o.x = 5 — ishlaydi, writable: true ochiq yozilgan. delete o.x — ishlamaydi: configurable yozilmagan, demak false (modulda TypeError: Cannot delete property 'x' of #<Object>, oddiy skriptda jim). Object.keys(o) — [], chunki enumerable ham false.
5. Accessor deskriptor: getter va setter
5.1 Ikki xil deskriptor
Getter'ning deskriptoriga qaraymiz:
const savat = {
taomlar: [35000],
get jami() {
return this.taomlar.reduce((s, n) => s + n, 0);
},
};
console.log(Object.getOwnPropertyDescriptor(savat, "jami"));Konsolda:
{
get: [Function: get jami],
set: undefined,
enumerable: true,
configurable: true
}Bu yerda value ham, writable ham yo'q. Ularning o'rnida — get va set. Bu — xususiyatning ikkinchi turi.
Sxemada ikki turni solishtiring — pastdagi ikki bayroq ikkalasida bir xil, yuqoridagilari esa farqli:
flowchart TD
X["Xususiyat deskriptori"] --> M["Ma'lumot deskriptori"]
X --> A["Accessor deskriptori"]
M --> MV["value + writable"]
A --> AG["get + set"]
MV --> U["enumerable + configurable"]
AG --> UMa'lumot deskriptori (data descriptor) — qiymatni o'zida saqlaydigan oddiy xususiyat: value, writable. Accessor deskriptori (accessor descriptor) — qiymat saqlamaydi, uning o'rniga funksiyalari bor: get, set. "Accessor" — inglizcha "kirish vositasi": u qiymatga "eshik" orqali kirishni beradi. enumerable va configurable — ikkalasida ham bor.
Ikkalasini aralashtirib bo'lmaydi:
Object.defineProperty({}, "jami", {
get() {
return 0;
},
value: 5,
});TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>Tarjimasi: "noto'g'ri xususiyat deskriptori: bir vaqtda accessor'lar va value yoki writable ni ko'rsatib bo'lmaydi". Mantiqiy: getter qiymatni har safar hisoblaydi — saqlangan value ga joy yo'q. Accessor xususiyatning "faqat o'qiladigan" bo'lishini writable emas, set ning yo'qligi belgilaydi.
5.2 Mavjud obyektga getter qo'shish
defineProperty bilan getter'ni obyekt yaratilgandan keyin ham qo'shish mumkin:
const bron = { odam: 9 };
Object.defineProperty(bron, "stollar", {
get() {
return Math.ceil(this.odam / 4);
},
enumerable: true,
});
console.log(bron.stollar); // 3
bron.odam = 13;
console.log(bron.stollar); // 4get() { ... } — metod shaklidagi oddiy funksiya, shuning uchun bron.stollar o'qilganda this — bron. Bu yerda arrow funksiya yozmang: get: () => this.odam — arrow'ning o'z this i yo'q (Function expression va arrow), u bron ni ko'rmaydi. Nega aynan shunday — this: to'rt qoida darsida.
Tekshirib ko'ring: Yuqoridagi
brongabron.stollar = 10yozildi. Nima bo'ladi? Deskriptordawritableyo'q — unda yozishni nima to'xtatadi?
Javob
Yozish rad etiladi: modulda TypeError: Cannot set property stollar of #<Object> which has only a getter, oddiy skriptda — jim. bron.stollar esa avvalgidek odam dan hisoblanadi. Accessor xususiyatda yozish ruxsatini set hal qiladi: set yo'q — yozib bo'lmaydi. Bu — Getter va setter darsidagi xatoning o'zi, faqat endi uning sababini deskriptorda ko'rasiz: set: undefined.
6. Ko'p xususiyat bilan ishlash
6.1 Ko'plik shakllari
Har ikki metodning "ko'plik" sheriklari bor:
| Bitta xususiyat | Hammasi birdaniga |
|---|---|
Object.getOwnPropertyDescriptor(o, "k") |
Object.getOwnPropertyDescriptors(o) |
Object.defineProperty(o, "k", d) |
Object.defineProperties(o, { k: d, ... }) |
getOwnPropertyDescriptors — obyektning har o'z xususiyati uchun deskriptor, kalitlari bo'yicha. defineProperties — xuddi shunday tuzilgan obyektni qabul qilib, ko'p xususiyatni bir yo'la yaratadi.
6.2 Getter'ni "tirik" holda nusxalash
Oldingi darsdagi muammoning yechimi — shu ikki metod birga:
const savat = {
taomlar: [35000],
get jami() {
return this.taomlar.reduce((s, n) => s + n, 0);
},
};
const tekis = { ...savat };
const toliq = Object.defineProperties(
{},
Object.getOwnPropertyDescriptors(savat),
);
tekis.taomlar = [1000];
toliq.taomlar = [1000, 2000];
console.log(tekis.jami); // 35000
console.log(toliq.jami); // 3000
console.log(toliq); // { taomlar: [ 1000, 2000 ], jami: [Getter] }Spread nusxasida jami — qotgan son. Deskriptor nusxasida esa — [Getter]: u o'z taomlar ini hisobladi. Spread qiymatlarni o'qib ko'chiradi, getOwnPropertyDescriptors esa xususiyatning tavsifini ko'chiradi — getter funksiyasining o'zini ham.
Bu ham sayoz nusxa: agar taomlar ga yangi massiv bermasdan, push qilsak, asl savat ham o'zgarardi (Sayoz va chuqur nusxalash).
Tekshirib ko'ring:
Object.assign({}, savat)getter'ni qanday ko'chiradi deb o'ylaysiz — spread kabimi yoki deskriptor kabimi?
Javob
Spread kabi: Object.assign getter'ni chaqiradi va natijani oddiy qiymat qilib yozadi. Uni Object.* metodlari darsida batafsil ko'ramiz. Getter'ni saqlab nusxalashning yagona tayyor yo'li — deskriptorlar orqali.
7. Ko'p uchraydigan xatolar
7.1 defineProperty dan keyin xususiyat "yo'qoldi"
Object.defineProperty(o, "x", { value: 1 }) — x konsolda va Object.keys da ko'rinmaydi. Tuzatish: kerakli bayroqlarni ochiq yozing: enumerable: true, writable: true, configurable: true.
7.2 Faqat o'qiladigan xususiyat jim o'zgarmaydi
Oddiy skriptda writable: false xususiyatga yozish xatosiz e'tiborsiz qoladi. Tuzatish: ishonch kerak bo'lsa, kodni modul sifatida ishga tushiring (.mjs, type="module") — u yerda TypeError chiqadi.
7.3 Cannot redefine property
configurable: false xususiyatni qayta sozlab bo'lmaydi. Tuzatish: configurable: false ni faqat haqiqatan "abadiy" xususiyatga qo'ying; o'zgarishi mumkin bo'lsa — true qoldiring.
7.4 value va get birga
Invalid property descriptor. Tuzatish: yoki value/writable, yoki get/set — birini tanlang.
7.5 Arrow funksiya getter sifatida
get: () => this.x — this obyektni ko'rmaydi. Tuzatish: get() { return this.x; }.
8. Mashqlar
1-mashq (oson): Deskriptorlarni o'qing
Uch xususiyatning deskriptorini chiqaring va har birida qaysi bayroq false ekanini ayting: Math.E, ["a"] massivining length i, { ism: "Ali" } ning ism i. Ishora: Object.getOwnPropertyDescriptor(obyekt, "kalit").
Yechim
const d1 = Object.getOwnPropertyDescriptor(Math, "E");
const d2 = Object.getOwnPropertyDescriptor(["a"], "length");
const d3 = Object.getOwnPropertyDescriptor({ ism: "Ali" }, "ism");
console.log(d1.writable, d1.enumerable, d1.configurable);
console.log(d2.writable, d2.enumerable, d2.configurable);
console.log(d3.writable, d3.enumerable, d3.configurable);Konsolda:
false false false
true false false
true true trueMath.E — matematik doimiy, hamma bayroq yopiq. Massiv length i — yoziladi, lekin sanalmaydi va o'chirilmaydi. Oddiy literal xususiyat — hamma bayroq ochiq.
2-mashq (o'rta): O'zgarmas buyurtma raqami
raqamBer(buyurtma, raqam) funksiyasini yozing. U buyurtmaga raqam xususiyatini qo'shsin: ko'rinadigan (Object.keys da bor), lekin o'zgartirib va o'chirib bo'lmaydigan. Natijani tekshiring: Object.keys da raqam bormi va deskriptorda writable qanday. Ishora: yozishga urinib ko'rmang — qat'iy rejimda b.raqam = 5 xato beradi va dastur shu qatorda to'xtaydi (xatoni ushlashni try...catch darsida o'rganamiz). "Yozib bo'ladimi?" savoliga deskriptordagi writable javob beradi.
Yechim
function raqamBer(buyurtma, raqam) {
Object.defineProperty(buyurtma, "raqam", {
value: raqam,
enumerable: true,
});
return buyurtma;
}
const b = raqamBer({ taom: "Manti", soni: 2 }, 101);
console.log(Object.keys(b)); // [ 'taom', 'soni', 'raqam' ]
console.log(b); // { taom: 'Manti', soni: 2, raqam: 101 }
const d = Object.getOwnPropertyDescriptor(b, "raqam");
console.log(d.writable); // falseFaqat enumerable: true yozildi — writable va configurable sukut bo'yicha false. Bu yerda sukut qiymatlari aynan kerakli narsa. Funksiya obyektni qaytaradi — shuning uchun raqamBer({...}, 101) ni bitta qatorda ishlatish qulay.
3-mashq (qiyin): To'liq nusxa funksiyasi
nusxaOl(obyekt) funksiyasini yozing: obyektning barcha o'z xususiyatlarini — getter'lar va sanalmaydiganlar bilan birga — yangi obyektga ko'chirsin. So'ng spread bilan solishtiring: getter'li, sanalmaydigan xususiyatli obyekt yarating va ikkala nusxada kalitlarni hamda getter natijasini chiqaring. Kalitlar uchun Object.getOwnPropertyNames(nusxa) ishlating — u Object.keys ga o'xshaydi, lekin sanalmaydigan kalitlarni ham beradi (to'liq — Object.* metodlari darsida).
Yechim
function nusxaOl(obyekt) {
return Object.defineProperties(
{},
Object.getOwnPropertyDescriptors(obyekt),
);
}
const bron = { odam: 6 };
Object.defineProperty(bron, "stollar", {
get() {
return Math.ceil(this.odam / 4);
},
});
const a = { ...bron };
const b = nusxaOl(bron);
a.odam = 12;
b.odam = 12;
console.log(Object.getOwnPropertyNames(a), a.stollar);
console.log(Object.getOwnPropertyNames(b), b.stollar);Konsolda:
[ 'odam' ] undefined
[ 'odam', 'stollar' ] 3Spread stollar ni umuman ko'chirmadi — u sanalmaydigan edi. nusxaOl esa uni ko'chirdi va getter'i "tirik": odam 12 bo'lgach, 3 ta stol hisobladi. Object.keys(b) faqat [ 'odam' ] berardi — stollar hali ham sanalmaydi, chunki deskriptor ham aynan ko'chdi.
4-mashq: Vazifalar qadami — qoldi ma'lumot emas
refactor/obyektlar branch'ida davom etamiz. Oldingi darsda holat ga qoldi getter'ini qo'shdik. Endi uning deskriptoriga qarang — DevTools konsolida:
Object.getOwnPropertyDescriptor(holat, "qoldi");
Object.keys(holat);qoldi — enumerable: true, Object.keys(holat) da vazifalar, keyingiId, filtr, tahrirId bilan bir qatorda turibdi. Lekin u ma'lumot emas — vazifalar dan hisoblanadi. 11-qismda ilova holatini saqlashni o'rganamiz (localStorage) — shunda { ...holat } kabi nusxalar olinadi, va hisoblanadigan son ma'lumot qatoriga qotgan holda tushib qolmasligi kerak.
qoldi ni sanalmaydigan qiling: Object.keys(holat) va { ...holat } da u ko'rinmasin, holat.qoldi esa avvalgidek ishlasin. Xulq o'zgarmasin.
Yechim
holat e'lonidan keyin bitta qator:
Object.defineProperty(holat, "qoldi", { enumerable: false });qoldi allaqachon bor — shuning uchun defineProperty faqat enumerable ni o'zgartiradi, getter'ga va configurable ga tegmaydi («Tuzoq: yozilmagan bayroq» bo'limidagi ogohlantirish).
Oldin va keyin Node'da solishtiring:
const holat = {
vazifalar: [{ bajarildi: false }, { bajarildi: true }],
filtr: "hammasi",
get qoldi() {
return statistika().qoldi;
},
};
function statistika() {
const guruhlar = Object.groupBy(holat.vazifalar, (v) =>
v.bajarildi ? "bajarilgan" : "faol",
);
return {
qoldi: guruhlar.faol?.length ?? 0,
bajarildi: guruhlar.bajarilgan?.length ?? 0,
};
}
console.log(Object.keys(holat), { ...holat }.qoldi);
Object.defineProperty(holat, "qoldi", { enumerable: false });
console.log(Object.keys(holat), { ...holat }.qoldi);
console.log(holat.qoldi);Konsolda:
[ 'vazifalar', 'filtr', 'qoldi' ] 1
[ 'vazifalar', 'filtr' ] undefined
1Oldin spread nusxasida qoldi: 1 — qotgan son. Endi nusxada qoldi yo'q, holat.qoldi esa ishlaydi. Nusxadan ham hisoblash kerak bo'lsa — getter'ni nusxadan emas, vazifalar dan qayta hisoblaysiz.
Brauzerda: "2 ta vazifa qoldi, 1 ta bajarildi", belgilash — "1 ta vazifa qoldi, 2 ta bajarildi", qo'shish va o'chirish — hisob to'g'ri. DevTools konsolida holat ni yozing: Chrome sanalmaydigan qoldi ni och rangda ko'rsatadi.
Commit: Vazifalar: qoldi getter'ini sanalmaydigan qil.
9. Real ishda
- Kutubxona va freymvorklar ichida. Vue 2 reaktivligi butunlay
Object.definePropertyga qurilgan edi: har xususiyat getter/setter'ga aylantirilardi va o'zgarish "ushlanardi". Vue 3 bu ishniProxybilan qiladi (ProxyvaReflect). - O'rnatilgan obyektlar.
Math.PI, massivlengthi, metodlar — hammasi deskriptorlar bilan sozlangan. Brauzer API'larining ko'p xususiyatlari (document.title,input.value) — accessor'lar. - Kod ko'rib chiqishda. Oddiy loyiha kodida
definePropertykam yoziladi — ko'pinchaclass, getter vaObject.freezeyetarli. Uchratsangiz — "bu yerda nimani yashirish yoki qotirish kerak bo'lgan?" deb so'rang. - Intervyu. "
enumerablenima?", "negafor...inmassivdalengthni bermaydi?", "Object.definePropertysukut qiymatlari qanday?" — middle darajasida so'raladi.
Xulosa
- Har xususiyatning deskriptori bor:
value+writable,enumerable,configurable(ma'lumot) yokiget+set,enumerable,configurable(accessor). - Literalda hamma bayroq
true;Object.definePropertybilan yangi xususiyatda yozilmagan bayroq —false. writable: false— yozish rad etiladi (moduldaTypeError, oddiy skriptda jim);enumerable: false—Object.keys, spread,for...inko'rmaydi;configurable: false— o'chirib va qayta sozlab bo'lmaydi.valuevagetbir deskriptorda bo'lmaydi; accessor'da arrow funksiya yozmang.Object.defineProperties({}, Object.getOwnPropertyDescriptors(o))— getter'larni "tirik" holda nusxalaydi.
Keyingi dars: Obyektni himoyalash: freeze, seal, preventExtensions — bitta xususiyatni emas, butun obyektni qotirishni va const nega bunga yetmasligini ko'ramiz.
Manbalar
- MDN: "Object.defineProperty()", "Object.getOwnPropertyDescriptor()", "Enumerability and ownership of properties" — developer.mozilla.org
- ECMAScript 2025 Language Specification: "The Property Descriptor Specification Type", "Object.defineProperty" — tc39.es/ecma262
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!