Белгилүү болгондой, объекттер касиеттерди камтышы мүмкүн.
Ушул убакка чейин биз мүлктү ачкыч-нарк жуп катары гана карап келдик. Бирок, чындыгында, объекттин касиети алда канча күчтүү жана ийкемдүү.
Бул бөлүмдө биз касиеттер үчүн кошумча конфигурация желектерин изилдейбиз, ал эми кийинкисинде аларды кантип ыңгайлаштырылган функцияларга, алуучтарга жана орнотуучуларга көзгө көрүнбөй айландыра аларыбызды көрөбүз.
касиетжелектери
Нарктан тышкары value
, объектинин касиеттери үч атайын атрибутка ээ («желек» деп аталат).
writable
– эгердеtrue
, мүлктү өзгөртүүгө болот, антпесе ал окуу үчүн гана болот.enumerable
– эгердеtrue
, сыпат циклдер менен саналат, антпесе циклдер аны этибарга албайт.configurable
– эгердеtrue
, касиетти жок кылууга болот жана бул атрибуттарды өзгөртүүгө болот, антпесе муну жасоо мүмкүн эмес.
Биз бул атрибуттарды көрө элекпиз, анткени алар көбүнчө жашырылган. Биз "кадимки жол менен" менчикти түзгөндө, алардын бардыгынын мааниси бар true
. Бирок биз аларды каалаган убакта өзгөртө алабыз.
Биринчиден, алардын учурдагы баалуулуктарын кантип алууга болорун карап көрөлү.
Object.getOwnPropertyDescriptor ыкмасы мүлк жөнүндө толук маалымат алууга мүмкүндүк берет .
Анын синтаксиси:
@A@let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);@A@
obj
Биз маалымат алган объект.
propertyName
Менчик аты.
Кайтаруучу маани объект болуп саналат, "мүлктүн дескриптору" деп аталат: ал менчиктин маанисин жана анын бардык желектерин камтыйт.
Мисалы:
@A@let user = {
name: "John"
};
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/* дескриптор свойства:
{
"value": "John",
"writable": true,
"enumerable": true,
"configurable": true
}
*/@A@
Желектерди өзгөртүү үчүн Object.defineProperty ыкмасын колдонсок болот .
Анын синтаксиси:
Object.defineProperty(obj, propertyName, descriptor)
obj
,propertyName
Тутканы колдонуу үчүн объект жана анын касиети.
descriptor
Колдонуу үчүн тутка.
Эгерде менчик бар болсо, defineProperty
анын желектерин жаңыртыңыз. Болбосо, ыкма көрсөтүлгөн маани жана желектер менен жаңы касиетти түзөт; кандайдыр бир желек ачык көрсөтүлбөсө, ага маани берилет false
.
Мисалы, бул name
бардык желекчелерге коюлган касиетти түзөт false
:
@A@let user = {};
Object.defineProperty(user, "name", {
value: "John"
});
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": "John",
"writable": false,
"enumerable": false,
"configurable": false
}
*/@A@
Муну биз "кадимки жол менен" касиетти түзгөн мурунку мисал менен салыштырыңыз user.name
: бул жолу бардык желектердин мааниси бар false
. Эгер бул бизге кереги жок болсо, биз аларга true
параметрде маанилерди ыйгарышыбыз керек descriptor
.
Эми желектерди колдонуу бизге эмне берерин көрсөткөн мисалдарды карап көрөлү.
Окуу үчүн гана
Келгиле, мүлктү user.name
окуу үчүн гана кылалы. Бул үчүн, желекти өзгөртүү writable
:
@A@let user = {
name: "John"
};
Object.defineProperty(user, "name", {
writable: false
});
user.name = "Pete"; // Ошибка: Невозможно изменить доступное только для чтения свойство 'name'@A@
Эми эч ким колдонуучунун атын өзгөртө албайт, эгерде алар тиешелүү желекти жаңы чалуу менен жаңыртмайынча defineProperty
.
Катуу эмес режимде, жок use strict
, окуу үчүн гана касиеттерге жана ушул сыяктууларга жазууда каталарды көрбөйбүз. Бирок бул операциялар дагы эле ийгиликтүү бүтпөйт. Желектин чектөөлөрүн бузган аракеттер жумшак режимде жөн гана унчукпай этибарга алынбайт.
Мына ошол эле мисал, бирок мулк нөлдөн баштап түзүлгөн:
@A@let user = { };
Object.defineProperty(user, "name", {
value: "John",
// для нового свойства необходимо явно указывать все флаги, для которых значение true
enumerable: true,
configurable: true
});
alert(user.name); // John
user.name = "Pete"; // Ошибка@A@
Саналбаган касиет
Эми өзүбүздүн ыкмабызды toString
кошолу user
.
Объекттерде орнотулган ыкма toString
саналбайт, ал циклде көрүнбөйт for..in
. Бирок биз өзүбүздүн методубузду жазсак toString
, цикл for..in
аны демейки боюнча чыгарат:
@A@let user = {
name: "John",
toString() {
return this.name;
}
};
// По умолчанию оба свойства выведутся:
for (let key in user) alert(key); // name, toString@A@
Эгер биз муну каалабасак, анда биз enumerable:false
. for..in
Андан кийин ал орнотулганга окшош циклде көрүнбөй калат toString
@A@let user = {
name: "John",
toString() {
return this.name;
}
};
Object.defineProperty(user, "toString", {
enumerable: false
});
// Теперь наше свойство toString пропало из цикла:
for (let key in user) alert(key); // name
Саналбаган касиеттер да кайтарылбайт Object.keys
:
alert(Object.keys(user)); // name@A@
Конфигурацияланбаган касиет
Конфигурацияланбаган касиет желеги ( configurable:false
) кээде кээ бир орнотулган объекттер жана касиеттер үчүн алдын ала коюлат.
Конфигурацияланбаган касиетти жок кылууга болбойт, анын атрибуттарын өзгөртүүгө болбойт.
Мисалы, касиет Math.PI
окуу үчүн гана, саналбайт жана конфигурацияланбайт:
@A@let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": 3.141592653589793,
"writable": false,
"enumerable": false,
"configurable": false
}
*/@A@
Башкача айтканда, программист маанини өзгөртө албайт Math.PI
же анын үстүнө жаза албайт.
@A@Math.PI = 3; // Ошибка, потому что writable: false
// delete Math.PI тоже не сработает
Биз ошондой эле өзгөртө албайбыз writable
:
// Ошибка, из-за configurable: false
Object.defineProperty(Math, "PI", { writable: true });@A@
Биз эч нерсе кыла албайбыз Math.PI
.
Мүлктү конфигурациялоо мүмкүн эмес деп аныктоо бир тараптуу жол. менен кайра өзгөртө албайбыз defineProperty
.
Белгилей кетчү нерсе, configurable: false
ал мүлктүн желектерин өзгөртүүгө жана аны жок кылууга жол бербейт. Муну менен сиз мүлктүн баасын өзгөртө аласыз.
Төмөнкү коддо мулк user.name
конфигурацияланбайт, бирок биз анын маанисин өзгөртө алабыз (анткени writable: true
).
@A@let user = {
name: "John"
};
Object.defineProperty(user, "name", {
configurable: false
});
user.name = "Pete"; // работает
delete user.name; // Ошибка@A@
Жана бул жерде биз аны "түбөлүк мөөр басылган" константага айлантабыз user.name
, ал орнотулган сыяктуу Math.PI
:
@A@let user = {
name: "John"
};
Object.defineProperty(user, "name", {
writable: false,
configurable: false
});
// теперь невозможно изменить user.name или его флаги
// всё это не будет работать:
user.name = "Pete";
delete user.name;
Object.defineProperty(user, "name", { value: "Pete" });@A@
Катуу эмес режимде окуу үчүн гана касиеттерге жана ушул сыяктууларга жазууда каталарды көрбөйбүз. Бул операциялар дагы эле ийгиликтүү бүтпөйт. Желектин чектөөлөрүн бузган аракеттер жумшак режимде жөн гана унчукпай этибарга алынбайт.
Object.defineProperties ыкмасы
Бир эле учурда бир нече касиеттерди аныктоого мүмкүндүк берген Object.defineProperties(obj, descriptors) ыкмасы бар.
Анын синтаксиси:
@A@Object.defineProperties(obj, {
prop1: descriptor1,
prop2: descriptor2
// ...
});
Мисалы:
Object.defineProperties(user, {
name: { value: "John", writable: false },
surname: { value: "Smith", writable: false },
// ...
});@A@
Ошентип, биз бир операцияда көптөгөн касиеттерди аныктай алабыз.
Object.getOwnPropertyDescriptors
Бардык мулк дескрипторлорун бир эле учурда алуу үчүн, сиз Object.getOwnPropertyDescriptors(obj) ыкмасын колдонсоңуз болот .
Бул ыкма менен бирге Object.defineProperties
объектти анын желектери менен клондоо үчүн колдонулушу мүмкүн:
@A@let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
Адатта, объектти клондоодо анын касиеттерин көчүрүү үчүн тапшырманы колдонобуз:
for (let key in user) {
clone[key] = user[key]
}@A@
…Бирок ал желектерди көчүрбөйт. Демек, эгер бизге "жакшы" клон керек болсо, аны колдонуу артык Object.defineProperties
.
Дагы бир айырмачылык, for..in
ал белгилерди жана саналбаган касиеттерди этибарга албайт жана бардыкObject.getOwnPropertyDescriptors
касиеттердин дескрипторлорун кайтарат .
Объектти глобалдык мөөр басуу
Мүлктүн дескрипторлору конкреттүү касиеттердин деңгээлинде иштешет.
Бирок бүт объектке кирүүнү чектеген ыкмалар да бар :
Объектке жаңы касиеттерди кошууга жол бербейт.
Мүлктөрдү кошууга/алып салууга тыюу салат. configurable: false
Учурдагы бардык касиеттер үчүн топтомдор .
касиеттерин кошууга/алып салууга/өзгөртүүсүнө тыюу салат. configurable: false, writable: false
Учурдагы бардык касиеттер үчүн топтомдор .
Ошондой эле аларды текшерүү ыкмалары бар:
false
Кошуу касиеттери өчүрүлгөн болсо кайтарат , болбосо true
.
true
Кыймылдарды кошуу/чыгаруу өчүрүлгөн болсо жана бар болгон бардык касиеттерге коюлган болсо, кайтарат configurable: false
.
true
Кошуу/алып салуу/өзгөртүү касиеттери өчүрүлгөн жана учурдагы бардык касиеттер деп коюлган болсо, кайтарат configurable: false, writable: false
.
Иш жүзүндө бул ыкмалар сейрек колдонулат.