Loading...

Желектер жана дескрипторлордун касиеттери

Желектер жана дескрипторлордун касиеттери

 

Белгилүү болгондой, объекттер касиеттерди камтышы мүмкүн.

Ушул убакка чейин биз мүлктү ачкыч-нарк жуп катары гана карап келдик. Бирок, чындыгында, объекттин касиети алда канча күчтүү жана ийкемдүү.

Бул бөлүмдө биз касиеттер үчүн кошумча конфигурация желектерин изилдейбиз, ал эми кийинкисинде аларды кантип ыңгайлаштырылган функцияларга, алуучтарга жана орнотуучуларга көзгө көрүнбөй айландыра аларыбызды көрөбүз.

касиетжелектери

Нарктан тышкары 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:falsefor..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 касиеттердин дескрипторлорун кайтарат .

Объектти глобалдык мөөр басуу

Мүлктүн дескрипторлору конкреттүү касиеттердин деңгээлинде иштешет.

Бирок бүт объектке кирүүнү чектеген ыкмалар да бар :

Object.preventExtensions(obj)

Объектке жаңы касиеттерди кошууга жол бербейт.

Объект Мөөрү(obj)

Мүлктөрдү кошууга/алып салууга тыюу салат. configurable: falseУчурдагы бардык касиеттер үчүн топтомдор .

Object.freeze(obj)

касиеттерин кошууга/алып салууга/өзгөртүүсүнө тыюу салат. configurable: false, writable: falseУчурдагы бардык касиеттер үчүн топтомдор .

Ошондой эле аларды текшерүү ыкмалары бар:

Object.isExtensible(obj)

falseКошуу касиеттери өчүрүлгөн болсо кайтарат , болбосо true.

Object.isSealed(obj)

trueКыймылдарды кошуу/чыгаруу өчүрүлгөн болсо жана бар болгон бардык касиеттерге коюлган болсо, кайтарат configurable: false.

Object.isFrozen(obj)

trueКошуу/алып салуу/өзгөртүү касиеттери өчүрүлгөн жана учурдагы бардык касиеттер деп коюлган болсо, кайтарат configurable: false, writable: false.

Иш жүзүндө бул ыкмалар сейрек колдонулат.