Loading...

Tип данных Symbol

Tип данных Symbol

 

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

Азырынча биз жиптерди гана көрдүк. Эми символдорду карап көрөлү, алар бизге кандай жакшылыктарды берип жатканын көрөлү.

Символдор

"символ" - уникалдуу идентификатор.

Функциянын жардамы менен жаңы символдор түзүлөт Symbol():

@A@// Создаём новый символ - id
let id = Symbol();@A@

Түзүлгөндө символго сыпаттама берилиши мүмкүн (аты деп да аталат), негизинен кодду оңдоо үчүн колдонулат:

 
 
@A@// Создаём символ id с описанием (именем) "id"
let id = Symbol("id");@A@

Каармандар уникалдуу болууга кепилдик берилет. Бир эле сыпаттамасы менен көптөгөн символдорду түзсөк да, алар баары бир башка символдор болуп кала берет. Сүрөттөмө эч нерсеге таасир этпеген жөн гана энбелги.

Мисалы, бул жерде бирдей сүрөттөлүш менен эки белги бар - бирок алар бирдей эмес:

@A@let id1 = Symbol("id");
let id2 = Symbol("id");

alert(id1 == id2); // false@A@

Эгер сиз Ruby же кандайдыр бир "символдору" бар башка программалоо тилин билсеңиз - этият болуңуз. JavaScript'теги символдордун өзүнүн өзгөчөлүктөрү бар жана аларды Ruby же башка тилдердеги каармандар катары кароого болбойт.

Символдор автоматтык түрдө саптарга айландырылбайт

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

Мисалы, alert төмөнкү ката берет

@A@let id = Symbol("id");
alert(id); // TypeError: Cannot convert a Symbol value to a string@A@

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

Эгерде биз чындап эле символду колдонууну кааласак , анда аны төмөнкүдөй alertыкма менен ачык түрдө конвертациялашыбыз керек :.toString()

@A@let id = Symbol("id");
alert(id.toString()); // Symbol(id), теперь работает@A@

symbol.descriptionЖе сыпаттаманы гана көрсөтүү үчүн мүлккө кире алабыз :

@A@let id = Symbol("id");
alert(id.description); // id@A@

"Жашыруун" касиеттери

Символдор кокусунан кирүүгө жана программанын башка бөлүктөрүнө кайра жазууга мүмкүн болбогон объекттердин "жашыруун" касиеттерин түзүүгө мүмкүндүк берет.

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

Бул үчүн символдук ачкычты колдонобуз:

@A@let user = {
  name: "Вася"
};

let id = Symbol("id");

user[id] = 1;

alert( user[id] ); // мы можем получить доступ к данным по ключу-символу

Symbol("id")Эмне үчүн сап эмес, колдонуу жакшыраак "id"?@A@

Объект userүчүнчү жактын кодуна таандык болгондуктан жана бул код аны менен да иштегендиктен, ага эч кандай талааларды кошпошубуз керек. Бул коопсуз эмес. Бирок символго байкабай кайрылуу кыйын, үчүнчү тараптын коду аны такыр көрүшү күмөн жана объектке талаа кошуу эч кандай көйгөй жаратпайт.

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

Үчүнчү тараптын коду бул үчүн өзүнүн символун түзө алат Symbol("id"):

@A@// ...
let id = Symbol("id");

user[id] = "Их идентификатор";@A@

Алар менен биздин идентификатордун ортосунда эч кандай конфликт болбойт, анткени каармандар аттары окшош болсо да, ар дайым уникалдуу.

"id"Бирок, эгерде символдун ордуна сап колдонсок , анда карама-каршылык болот :

@A@let user = { name: "Вася" };

// Объявляем в нашем скрипте свойство "id"
user.id = "Наш идентификатор";

// ...другой скрипт тоже хочет свой идентификатор...

user.id = "Их идентификатор"@A@
// Ой! Свойство перезаписано сторонней библиотекой!

Сөзмө-сөз объекттеги каармандар

Эгерде биз сөзмө-сөз объект декларациясында символду колдонгубуз келсе {...}, ал чарчы кашаага алынышы керек.

Бул сыяктуу:

@A@let id = Symbol("id");

let user = {
  name: "Вася",
  [id]: 123 // просто "id: 123" не сработает
};@A@

Себеби, биз id"id" сабын эмес, өзгөрмөнүн маанисин ачкыч катары колдонушубуз керек.

Символдор циклде for... тарабынан этибарга алынбайт

Ачкычтары символ болгон касиеттер айланбайт for..in.

Мисалы:

@A@let id = Symbol("id");
let user = {
  name: "Вася",
  age: 30,
  [id]: 123
};
for (let key in user) alert(key); // name, age (свойства с ключом-символом нет среди перечисленных)

// хотя прямой доступ по символу работает
alert( "Напрямую: " + user[id] );@A@

Бул "мүнөзүн жашыруу" жалпы принцибинин бир бөлүгү. Эгерде башка китепкана же скрипт биздин объект менен иштесе, анда итерациялоодо алар биздин каймана касиетибизди байкабай кабыл алышпайт. Object.keys(user)каармандарга да көңүл бурбайт.

Бирок Object.assign , циклден айырмаланып for..in, саптын да, символдун да касиеттерин көчүрөт:

@A@let id = Symbol("id");
let user = {
  [id]: 123
};

let clone = Object.assign({}, user);

alert( clone[id] ); // 123@A@

Бул жерде эч кандай парадокс же карама-каршылык жок. Мына ушундай ниеттенип жатат. Идея, биз объекттерди клондоштурууда же бириктиргенде, биз адатта бардык касиеттерди (анын ичинде idжогорудагы мисал сыяктуу символикалык ачкычтары бар касиеттерди) көчүргүбүз келет.

Глобалдык символдор

Демек, биз көргөндөй, адатта, бардык каармандар, алардын аттары бирдей болсо да, уникалдуу болуп саналат. Бирок, кээде, тескерисинче, бир эле аталыштагы символдордун бир бүтүм болушун каалайбыз. Мисалы, биздин тиркеменин ар кандай бөлүктөрү "id"дал ошол эле касиетти билдирген символго кирүүнү каалайт.

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

Реестрден белгини окуу (же болбосо, түзүү) үчүн Symbol.for(key).

Ал глобалдык реестрди текшерет жана эгер ал аты менен символду камтыса key, аны кайтарат, антпесе жаңы символ түзүлүп Symbol(key), реестрге ачкычтын астында жазылат key.

Мисалы:

@A@// читаем символ из глобального реестра и записываем его в переменную
let id = Symbol.for("id"); // если символа не существует, он будет создан

// читаем его снова и записываем в другую переменную (возможно, из другого места кода)
let idAgain = Symbol.for("id");

// проверяем -- это один и тот же символ
alert( id === idAgain ); // true@A@

Реестрде камтылган символдор глобалдык символдор деп аталат . Эгер сизге коддун бардык жеринде жеткиликтүү символ керек болсо, глобалдык символдорду колдонуңуз.

Ruby окшош

Кээ бир программалоо тилдеринде, мисалы, Ruby, ар бир ат үчүн бир символ (сүрөттөө) бар жана бир эле аталыштагы ар кандай символдор болушу мүмкүн эмес.

JavaScript'те, биз көрүп тургандай, бул билдирүү глобалдык символдор үчүн гана туура.

Symbol.keyFor

Symbol.for(key)Символду аты боюнча издегенден башка глобалдык символдор үчүн тескери ыкма бар: Symbol.keyFor(sym), ал, тескерисинче, глобалдык символду алып, анын атын кайтарат.

Мисалга:

@A@// получаем символ по имени
let sym = Symbol.for("name");
let sym2 = Symbol.for("id");
// получаем имя по символу
alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id@A@

Методдун ичинде Symbol.keyForсимволдун атын табуу үчүн глобалдык символдор реестри колдонулат. Ошентип, бул ыкма глобалдык эмес каармандар үчүн иштебейт. Эгерде символ глобалдык эмес болсо, метод аны таба албай калат жана кайтып келет undefined.

Бирок, мүлк бардык символдор үчүн жеткиликтүү description.

Мисалы:

@A@let globalSymbol = Symbol.for("name");
let localSymbol = Symbol("name");

alert( Symbol.keyFor(globalSymbol) ); // name, глобальный символ
alert( Symbol.keyFor(localSymbol) ); // undefined для неглобального символа

alert( localSymbol.description ); // name@A@

Системанын символдору

JavaScriptтин өзүндө колдонулган көптөгөн "системалык" белгилер бар жана биз аларды объекттердин кандайча иш алып барышынын ар кандай аспектилерин ыңгайлаштыруу үчүн колдоно алабыз.

Бул белгилер Белгилүү символдор таблицасындагы спецификацияда келтирилген :

  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.iterator
  • Symbol.toPrimitive
  • …жана башка.

Атап айтканда, Symbol.toPrimitiveал примитивге айландырыла турган объекттин эрежелерин сүрөттөөгө мүмкүндүк берет. Биз анын колдонулушун жакында көрөбүз.

Ошондой эле тилдин тиешелүү өзгөчөлүктөрүн изилдегенде башка системалык белгилер менен да жакында таанышабыз.

Бардыгы

Символ (символ) – уникалдуу идентификаторлорду түзүү үчүн колдонулган примитивдүү маалымат түрү.

Символдор функцияны чакыруу менен түзүлөт Symbol(), ал символдун сыпаттамасынан (аты) өтүшү мүмкүн.

Символдор бир эле атка ээ болсо да, алар башка символдор. Эгерде биз бир эле аталыштагы символдор бирдей болушун кааласак, анда биз глобалдык реестрди колдонушубуз керек: чалуу аты Symbol.for(key)менен глобалдык символду кайтарат (же түзөт) . Бир эле аргумент менен keyбуйрукка бир нече чалуулар бир эле белгини кайтарат.Symbol.for

Символдордун эки негизги колдонулушу бар:

  1. Объекттердин "жашыруун" касиеттери.

    Эгерде биз башка скриптке же китепканага "тиешелүү" объектке касиет кошкубуз келсе, анда биз символ түзүп, аны ачкыч катары колдоно алабыз. Белги касиети ичинде пайда болбойт for..in, андыктан ал башкалар менен бирге кокустан иштетилбейт. Ошондой эле, ал түз жетүү аркылуу өзгөртүлбөйт, анткени башка скрипт биздин символду билбейт. Ошентип, мүлк кокустан кайра жазуудан же колдонуудан корголот.

    Ошентип, каармандын касиеттерин колдонуу менен биз жашыргыбыз келген, бирок башкалар көрбөгөн нерселерди жашыра алабыз.

  2. JavaScript тарабынан ички колдонулган көптөгөн системалык белгилер бар Symbol.*. Биз аларды бир катар объекттердин орнотулган жүрүм-турумун өзгөртүү үчүн колдоно алабыз. Мисалы, кийинки бөлүмдөрдө биз итераторлорSymbol.iterator үчүн , объекттерди примитивдерге айландырууну ыңгайлаштыруу үчүн жана башкаларды колдонобуз .Symbol.toPrimitive

Белгилер техникалык жактан 100% жашырылган эмес. Object.getOwnPropertySymbols(obj) орнотулган методу бар - анын жардамы менен символдук баскычтар менен объекттин бардык касиеттерин ала аласыз. Ошондой эле Reflect.ownKeys(obj) ыкмасы бар , ал бардык объект ачкычтарын, анын ичинде символ баскычтарын кайтарат . Ошентип, алар толугу менен жашырылган эмес. Бирок көпчүлүк китепканалар, орнотулган ыкмалар жана синтаксистик түзүлүштөр бул ыкмаларды колдонушпайт.