Xususiyatlarning ikki turi mavjud.
Birinchi tur ma’lumotlar xususiyatlari. Biz allaqachon ular bilan qanday ishlashni bilamiz. Aslida, biz hozirgacha ishlatib kelayotgan barcha xususiyatlar ma’lumotlar xususiyatlari edi.
Ikkinchi turdagi xususiyatlar – bu yangi narsa. Bu kiruvchi xususiyatlar. Ular asosan qiymatni olish va sozlash bo’yicha ishlaydigan funktsiyalardir, ammo tashqi kodning odatiy xususiyatlariga o’xshaydi.
Getters va setters
Kiruvchi xususiyatlari “getter” va “setter” usullari bilan ifodalanadi. Obyektda ular get
va set
bilan belgilanadi:
let obj = {
get propName() {
// getter, obj.propName olishda bajarilgan kod
},
set propName(value) {
// setter, obj.propName = value ni o'rnatishda bajarilgan kod
}
};
Getter obj.propName
o’qilganda ishlaydi, setter – tayinlanganda.
Masalan, bizda user
obyekti ismi
va familiyasi
mavjud:
let user = {
name: "John",
surname: "Smith",
};
Endi biz “to’liq nom” xususiyatini qo’shmoqchimiz, bu “Jon Smit” bo’lishi kerak. Albatta, biz mavjud ma’lumotlarni nusxa ko’chirishni xohlamaymiz, shuning uchun biz uni kiruvchi sifatida amalga oshirishimiz mumkin:
let user = {
name: "John",
surname: "Smith",
get fullName() {
return `${this.name} ${this.surname}`;
}
};
alert(user.fullName); // John Smith
Tashqaridan, kiruvchining xususiyati odatdagidek ko’rinadi. Kiruvchi xususiyatlarining g’oyasi shu. user.fullName
funktsiyadak chaqiurmaymiz, odatdagidek o’qiymiz: getter sahna ortida ishlaydi.
Hozirga kelib, fullName
faqat getter ga ega. Agar user.fullName=
ni belgilashga harakat qilsak, xato bo’ladi.
Buni user.fullName
uchun setter qo’shib tuzatamiz:
let user = {
name: "John",
surname: "Smith",
get fullName() {
return `${this.name} ${this.surname}`;
},
set fullName(value) {
[this.name, this.surname] = value.split(" ");
}
};
// set fullName berilgan qiymat bilan bajariladi.
user.fullName = "Alice Cooper";
alert(user.name); // Alice
alert(user.surname); // Cooper
Endi bizda “virtual” xususiyat mavjud. Bu o’qilishi mumkin va yozilishi mumkin, lekin aslida mavjud emas.
Xususiyat get prop()
yoki set prop()
bilan aniqlangandan so’ng, bu ma’lumotlarning xususiyati emas, balki kiruvchi xususiyatdir.
- Agar getter bo’lsa – biz
object.prop
ni o’qiymiz, yoki biz o’qiy olmaymiz. - Agar setter bo’lsa – biz
object.prop=...
ni o’rnatamiz, yoki biz qila olmaymiz.
Va har qanday holatda ham biz kiruvchi xususiyatini o'chirib tashlay olmaymiz
.
Kiruvchi tavsiflovchilari(deskriptorlar)
Ma’lumotlar xususiyatlari bilan taqqoslaganda, kiruvchi xususiyatlari uchun tavsiflovchilar har xil.
Kiruvchi xususiyatlari uchun value
va writeable
mavjud emas, aksincha get
va set
funktsiyalari mavjud.
Shunday qilib, kiruvchi deskriptor quyidagilarga ega bo’lishi mumkin:
get
– argumentlarsiz funktsiya, xususiyat o’qilganda ishlaydi,set
– xususiyati o’rnatilganda chaqiriladigan bitta argumentli funktsiya,enumerable
– ma’lumotlar xususiyatlari bilan bir xil,configurable
– ma’lumotlar xususiyatlari bilan bir xil.
Masalan, defineProperty
bilan fullName
ga kirish vositasini yaratish uchun biz get
va set
bilan deskriptorni topshirishimiz mumkin:
let user = {
name: "John",
surname: "Smith"
};
Object.defineProperty(user, 'fullName', {
get() {
return `${this.name} ${this.surname}`;
},
set(value) {
[this.name, this.surname] = value.split(" ");
}
});
alert(user.fullName); // John Smith
for(let key in user) alert(key); // name, surname
Iltimos, yana bir bor e’tibor bering, xususiyat ikkalasi ham emas, balki kiruvchi yoki ma’lumotlar xususiyati bo’lishi mumkin.
Agar biz bir xil deskriptorda get
va value
ni berishga harakat qilsak, xato bo’ladi:
// Error: Invalid property descriptor.
Object.defineProperty({}, 'prop', {
get() {
return 1
},
value: 2
});
Aqlli getters/setters
Getters/setters “real” xususiyat qiymatlari ustidan ko’proq nazoratni olish uchun ularni o’ram sifatida ishlatilishi mumkin.
Masalan, user
uchun juda qisqa nomlarni taqiqlashni istasak, name
ni _name
maxsus xususiyatida saqlashimiz mumkin. Va setter tayinlashlarni filtrlash:
let user = {
get name() {
return this._name;
},
set name(value) {
if (value.length < 4) {
alert("Ism juda qisqa, kamida 4 ta belgi kerak");
return;
}
this._name = value;
},
};
user.name = "Pete";
alert(user.name); // Pete
user.name = ""; // Ism juda qisqa...
Texnik jihatdan, tashqi kod user._name
yordamida to’g’ridan-to’g’ri nomga kirishi mumkin. Ammo "_"
"pastki chizig’i bilan boshlanadigan xususiyatlar ichki xususiyatga ega va obyekt tashqarisidan ularga tegmaslik kerakligi to’g’risida keng tarqalgan kelishuv mavjud.
Moslik uchun foydalanish
Getter va setterlarning orqasida turgan ajoyib g’oyalardan biri – ular “normal” ma’lumotlar xususiyatini boshqarish va har qanday vaqtda uni sozlash imkonini beradi.
Masalan, biz name
va age
ma’lumotlar xususiyatlaridan foydalangan holda foydalanuvchi obyektlarini amalga oshirishni boshladik:
function User(name, age) {
this.name = name;
this.age = age;
}
let john = new User("John", 25);
alert(john.age); // 25
…Ammo ertami-kechmi ishlar o’zgarishi mumkin. yoshni
o’rniga tug'ilgan kunni
saqlashga qaror qilishimiz mumkin, chunki bu aniqroq va qulayroq:
function User(name, birthday) {
this.name = name;
this.birthday = birthday;
}
let john = new User("John", new Date(1992, 6, 1));
Endi age
xususiyatidan foydalanadigan eski kodni bilan nima qilish kerak?
Biz bunday joylarni topishga va ularni tuzatishga urinib ko’rishimiz mumkin, ammo bu vaqtni talab qiladi va agar bu kod boshqa odamlar tomonidan yozilgan bo’lsa, buni amalga oshirish qiyin bo’lishi mumkin. Va bundan tashqari, age
– bu user
da saqlash yaxshi narsa, shunday emasmi? Ba’zi joylarda bu biz xohlagan narsadir.
age
uchun getter qo’shilishi muammoni engillashtiradi:
function User(name, birthday) {
this.name = name;
this.birthday = birthday;
// yoshi joriy sana va tug'ilgan kunidan boshlab hisoblanadi
Object.defineProperty(this, "age", {
get() {
let todayYear = new Date().getFullYear();
return todayYear - this.birthday.getFullYear();
}
});
}
let john = new User("John", new Date(1992, 6, 1));
alert( john.birthday ); // birthday mavjud
alert( john.age ); // ...shuningdek, age
Endi eski kod ham ishlaydi va bizda qo’shimcha xususiyat mavjud.
Izohlar
<code>
yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>
yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen…)