Obyekt xossalari konfiguratsiyasi

Xossa bayroqlari va deskriptorlari

Biz obyekt xossalarini oddiy "kalit: qiymat" juftliklari deb bilamiz. Aslida esa xossa โ€” bu ancha moslashuvchan va boshqariladigan narsa. Ushbu darsda xossalarning yashirin bayroqlari (flags) bilan tanishamiz va ularni deskriptorlar orqali qanday sozlashni o'rganamiz.

Xossa bayroqlari nima?

Obyekt xossalari qiymatdan tashqari yana uchta maxsus atribut โ€” bayroq (flag)ga ega. Ular true yoki false qiymat oladi:

Biz xossani odatdagidek yaratganimizda, bu uchala bayroq avtomatik ravishda true qiymatini oladi. Shuning uchun biz ularni odatda sezmaymiz โ€” hamma narsa "erkin" ishlaydi.

Bu darsda ko'rib chiqiladigan bayroqlar faqat ma'lumot xossalari (data properties) uchun amal qiladi. Keyingi darsda ko'radigan getter/setter aksessor xossalari boshqacha atributlarga ega.

Object.getOwnPropertyDescriptor

Xossa haqidagi to'liq ma'lumotni โ€” qiymati va barcha bayroqlarini โ€” bilish uchun Object.getOwnPropertyDescriptor metodidan foydalanamiz. Sintaksisi quyidagicha:

let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);

Natijada "xossa deskriptori" (property descriptor) deb ataladigan obyekt qaytadi. U qiymatni va barcha bayroqlarni saqlaydi. Quyidagi misolni ishga tushiring:

getdescriptor.js
// natija shu yerda chiqadi

Ko'rib turganingizdek, oddiy usulda yaratilgan xossada value, writable, enumerable va configurablening hammasi truega teng.

Object.defineProperty

Bayroqlarni o'zgartirish uchun Object.defineProperty metodidan foydalanamiz:

Object.defineProperty(obj, propertyName, descriptor);

Agar bunday nomli xossa mavjud bo'lsa, defineProperty uning bayroqlarini yangilaydi. Aks holda esa berilgan qiymat va bayroqlar bilan yangi xossa yaratadi; bunda ko'rsatilmagan bayroq false deb qabul qilinadi.

defineproperty.js
// natija shu yerda chiqadi
Diqqat qiling: yuqoridagi misolda xossa defineProperty orqali yaratildi, lekin bayroqlar aniq ko'rsatilmadi. Shuning uchun writable, enumerable va configurable avtomatik false bo'lib qoladi โ€” bu oddiy user.name = "Jasur"dan tubdan farq qiladi!

writable โ€” faqat o'qish uchun xossa

name xossasini faqat o'qish uchun (read-only) qilib qo'yamiz. Buning uchun writableni falsega o'zgartiramiz. Endi hech kim uning qiymatini o'zgartira olmaydi:

writable.js
// natija shu yerda chiqadi
Odatdagi (sokin) rejimda o'zgartirishga urinish jimgina e'tiborsiz qoldiriladi. Ammo faylning boshida "use strict" yozilgan qat'iy rejimda esa bu urinish xatolik (TypeError) chaqiradi.

Faqat o'qish uchun xossani o'zgartirishga urinish qat'iy rejimda qanday xato berishini ko'rsatuvchi misol:

writable-strict.js
// natija shu yerda chiqadi

enumerable โ€” sanashdan yashirish

Endi obyektga maxsus toString metodini qo'shamiz. Odatda obyektlardagi barcha xossalar for..in siklida ko'rinadi, bu esa har doim ham kerak emas. enumerable: false qilib, xossani sikllardan va Object.keysdan yashiramiz:

enumerable.js
// natija shu yerda chiqadi
Enumerable bo'lmagan xossalar Object.keys(), Object.values() va for..in natijasidan tushib qoladi, lekin ular baribir mavjud โ€” ularga to'g'ridan-to'g'ri (user.toString) murojaat qilsa bo'ladi.

configurable โ€” o'zgarmas xossa

configurable: false bayrog'i ba'zi muhim ichki xossalarga o'rnatilgan bo'ladi. Bunday xossani delete orqali o'chirib bo'lmaydi va uning bayroqlarini defineProperty orqali o'zgartirib ham bo'lmaydi.

Masalan, Math.PI faqat o'qiladigan, sanalmaydigan va sozlanmaydigan (non-configurable) xossadir. Buni tekshiramiz:

configurable-mathpi.js
// natija shu yerda chiqadi

Xossani "abadiy muhrlash" uchun uni bir vaqtda writable: false va configurable: false qilib qo'yish odatiy usuldir. Shundan so'ng qiymatni ham, bayroqlarni ham hech kim o'zgartira olmaydi:

configurable-seal.js
// natija shu yerda chiqadi
configurable: false โ€” bu bir tomonlama harakat. Xossani sozlanmas qilib qo'ygandan so'ng, uni defineProperty orqali qaytadan sozlanadigan (configurable: true) qilib bo'lmaydi. Bu qaytmas amaldir.
Muhim istisno: agar configurable false, lekin writable true bo'lsa, qiymatni hali ham o'zgartirish mumkin, shuningdek writableni truedan falsega o'zgartirish ham ruxsat etiladi (aksincha emas).

Object.defineProperties

Bir vaqtning o'zida bir nechta xossani e'lon qilish uchun Object.defineProperties qulay:

Object.defineProperties(obj, {
  prop1: descriptor1,
  prop2: descriptor2
  // ...
});
defineproperties.js
// natija shu yerda chiqadi

Object.getOwnPropertyDescriptors

Barcha xossalarning deskriptorlarini bir vaqtda olish uchun Object.getOwnPropertyDescriptors(obj) ishlatiladi. U Object.defineProperties bilan birga obyektni bayroqlari bilan birga nusxalash uchun juda foydali:

let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));

Odatdagi for..in yoki Object.assign nusxalashi bayroqlarni ko'chirmaydi va sanalmaydigan (non-enumerable) xossalarni tashlab ketadi. Yuqoridagi usul esa xossani to'liq, barcha bayroqlari bilan ko'chiradi:

descriptors-clone.js
// natija shu yerda chiqadi

Butun obyektni himoyalash

Yuqoridagi metodlar bitta xossaga ta'sir qiladi. Butun obyektni cheklovchi uchta "global" metod ham bor:

Ular uchun mos tekshiruv metodlari mavjud: Object.isExtensible(obj), Object.isSealed(obj) va Object.isFrozen(obj).

freeze.js
// natija shu yerda chiqadi
Amaliyotda bu global metodlar juda kam ishlatiladi. Ular obyektni chindan ham o'zgarmas qilish kerak bo'lgan maxsus holatlarda foydali.

Xulosa