Symbol
Symbol
(символ) – це вбудований об'єкт, чий конструктор повертає примітив symbol
– котрий також звуть символьним значенням або просто символом, і котрий гарантовано є унікальним. Символи нерідко використовуються для додання до об'єкта унікальних ключів властивостей, котрі не конфліктуватимуть з жодними ключами, які може додати до цього об'єкта якийсь інший код, і котрі приховані від будь-яких механізмів, за допомогою яких інший корд здебільшого буде звертатися до цього об'єкта. Таким чином доступна певного роду слабка інкапсуляція, або ж слабка форма приховування інформації.
Кожний виклик Symbol()
гарантовано повертає унікальний символ. Кожний виклик Symbol.for("key")
повертає той самий символ для того самого значення "key"
. Коли викликається Symbol.for("key")
, то якщо символ з переданим ключем може бути знайдений у глобальному реєстрі символів — цей символ повертається. Інакше – створюється і додається до глобального реєстру символів за переданим ключем новий символ, після чого – повертається.
Опис
Для створення нового примітивного символу слід написати Symbol()
з необов'язковим рядком як його описом:
const sym1 = Symbol();
const sym2 = Symbol("foo");
const sym3 = Symbol("foo");
Код вище створює три нові символи. Зверніть увагу, що Symbol("foo")
не зводить рядок "foo"
до символу. Він щораз створює новий символ:
Symbol("foo") === Symbol("foo"); // false
Наступний код, з оператором new
, викине TypeError
:
const sym = new Symbol(); // TypeError
Це не дає розробникам створювати замість нових символьних значень явні об'єкти-обгортки Symbol
, але може здивувати, адже загалом створення явних об'єктів-обгорток навколо примітивних типів даних – можливо (наприклад, new Boolean
, new String
і new Number
).
Коли справді треба створити об'єкт-обгортку Symbol
, для цього можна використати функцію Object()
:
const sym = Symbol("foo");
typeof sym; // "symbol"
const symObj = Object(sym);
typeof symObj; // "object"
Через те, що символи – єдиний примітивний тип даних, що має ідентичність за посиланням (тобто не можна створити той самий символ двічі), вони у певному розумінні поводяться як об'єкти. Наприклад, щодо них працює збирач сміття, а тому вони можуть зберігатися в об'єктах WeakMap
, WeakSet
, WeakRef
і FinalizationRegistry
.
Спільні символи у глобальному реєстрі символів
Код вище, застосовуючи функцію Symbol()
, створює символ, чиє значення залишається унікальним протягом всього часу роботи програми. Для створення символів, доступних у різних файлах і навіть різних царинах (кожна з яких має власну глобальну область видимості), слід застосовувати методи Symbol.for()
і Symbol.keyFor()
– для задання та отримання символів з глобального реєстру символів.
Зверніть увагу, що "глобальний реєстр символів" є лише уявною концепцією, котра може не відповідати жодній внутрішній структурі даних рушія JavaScript – і навіть коли такий реєстр існує, його вміст недоступний кодові на JavaScript ніяким іншим чином, окрім методів for()
і keyFor()
.
Метод Symbol.for(tokenString)
приймає рядковий ключ і повертає символьне значення з реєстру, а Symbol.keyFor(symbolValue)
приймає символьне значення і повертає рядковий ключ, котрий цьому значенню відповідає. Ці методи є взаємно оберненими, тож код нижче дає true
:
Symbol.keyFor(Symbol.for("tokenString")) === "tokenString"; // true
Через те, що реєстрові символи можуть бути створені будь-де, вони поводяться майже точно так само, як рядки, котрі вони обгортають. Тому такі символи не гарантовано унікальні та не підлягають збиранню сміття. Унаслідок цього реєстрові символи заборонені в об'єктах WeakMap
, WeakSet
, WeakRef
і FinalizationRegistry
.
Загальновідомі символи
Усі статичні властивості конструктора Symbol
самі є символами, чиї значення – сталі для всіх царин. Вони відомі як загальновідомі символи, і їхнє призначення – служити "протоколами" для певних вбудованих операцій JavaScript, даючи користувачам змогу налаштувати поведінку мови. Наприклад, якщо функція-конструктор має метод з іменем Symbol.hasInstance
, то такий метод міститиме логіку для оператора instanceof
.
До появи загальновідомих символів JavaScript, для реалізації певних вбудованих операцій, використовував звичайні властивості. Наприклад, функція JSON.stringify
намагається викликати на кожному об'єкті метод toJSON()
, а функція String
викликає на об'єкті методи toString()
і valueOf()
. Проте, із доданням до мови більшої кількості операцій, виділення кожній з них "магічної властивості" могло зламати зворотну сумісність й ускладнити роботу з логікою мови. Загальновідомі символи дають кастомізаціям змогу бути "невидимими" для звичайного коду, котрий зазвичай зчитує лише рядкові властивості.
Примітка: Раніше специфікація користувалася для позначення загальновідомих символів записом
@@<symbol-name>
. Наприклад,Symbol.hasInstance
записувався як@@hasInstance
, а методArray.prototype[Symbol.iterator]()
називавсяArray.prototype[@@iterator]()
. Цей запис більше не вживається у специфікації, але його досі можна зустріти в старій документації й обговореннях.
Загальновідомі символи не мають концепції збирання збирачем сміття, тому що вони входять до фіксованого набору і є унікальними протягом усього життя програми, подібно до вбудованих об'єктів, як то Array.prototype
, тож вони також дозволені в об'єктах WeakMap
, WeakSet
, WeakRef
і FinalizationRegistry
.
Пошук на об'єктах символьних властивостей
Метод Object.getOwnPropertySymbols()
повертає масив символів і дає змогу знайти на переданому об'єкті символьні властивості. Зверніть увагу, що кожний об'єкт ініціалізується без власних символьних властивостей, тож цей об'єкт буде порожнім, якщо не задати на об'єкті якісь символьні властивості.
Конструктор
Symbol()
Повертає примітивні значення типу Symbol. Викидає помилку, коли викликається з
new
.
Статичні властивості
Статичними властивостями є загальновідомі символи. У описах цих символів ми використовуємо вирази виду "Symbol.hasInstance
– це метод, що визначає…", але майте на увазі, що такі вирази – звертання до семантики методу об'єкта, що містить цей символ як назву свого методу (тому що загальновідомі символи діють як "протоколи"), а не опис значення самого символу.
Symbol.asyncIterator
Метод, що повертає усталений AsyncIterator об'єкта. Використовується циклом
for await...of
.Symbol.hasInstance
Метод, що визначає те, чи впізнає об'єкт-конструктор певний об'єкт як свій примірник. Використовується оператором
instanceof
.Symbol.isConcatSpreadable
Булеве значення, котре вказує на те, чи сплющується об'єкт до своїх елементів масиву. Використовується
Array.prototype.concat()
.Symbol.iterator
Метод, що повертає усталений ітератор об'єкта. Використовується циклом
for...of
.Symbol.match
Метод, що виконує зіставлення з рядком, а також використовується для з'ясування того, чи може об'єкт вживатися як регулярний вираз. Використовується методом
String.prototype.match()
.Symbol.matchAll
Метод, котрий повертає ітератор, котрий видає збіги регулярного виразу в рядку. Використовується методом
String.prototype.matchAll()
.Symbol.replace
Метод, котрий замінює підрядки збігу в рядку. Використовується методом
String.prototype.replace()
.Symbol.search
Метод, котрий повертає індекс всередині рядка, який дає збіг з регулярним виразом. Використовується методом
String.prototype.search()
.Symbol.species
Функція-конструктор, котра використовується для створення похідних об'єктів.
Symbol.split
Метод, котрий розбиває рядок за індексами, що дають збіг з регулярним виразом. Використовується методом
String.prototype.split()
.Symbol.toPrimitive
Метод, котрий перетворює об'єкт на примітивне значення.
Symbol.toStringTag
Рядкове значення, котре використовується як усталений опис об'єкта. Використовується методом
Object.prototype.toString()
.Symbol.unscopables
Об'єктне значення, чиї власні й успадковані імена властивостей виключаються зі зв'язувань середовища інструкції
with
для асоційованого об'єкта.
Статичні методи
Symbol.for()
Шукає серед наявних зареєстрованих символів у глобальному реєстрі Symbol за переданим ключем
key
і повертає, якщо знайдено. Інакше – створюється та реєструється новий символ із заданим ключемkey
.Symbol.keyFor()
Дістає зі глобального реєстру символів спільний символьний ключ для переданого символу.
Властивості примірника
Ці властивості означені на Symbol.prototype
і спільні для всіх примірник Symbol
.
Symbol.prototype.constructor
Функція-конструктор, що створила об'єкт-примірник. Для примірників
Symbol
початковим значенням є конструкторSymbol
.Symbol.prototype.description
Рядок лише для зчитування, що містить опис символу.
Symbol.prototype[Symbol.toStringTag]
Початкове значення властивості
[Symbol.toStringTag]
– рядок"Symbol"
. Ця властивість використовується в методіObject.prototype.toString()
. Проте через те, щоSymbol
має власний методtoString()
, то ця властивість не використовується, якщо не викликатиObject.prototype.toString.call()
з символьним значенням якthisArg
.
Методи примірника
Symbol.prototype.toString()
Повертає рядок, що містить опис символу. Заміщає метод
Object.prototype.toString()
.Symbol.prototype.valueOf()
Повертає той же символ. Заміщає метод
Object.prototype.valueOf()
.Symbol.prototype[Symbol.toPrimitive]()
Повертає той же символ.
Приклади
Використання з символами оператора typeof
Оператор typeof
може допомогти впізнати символи.
typeof Symbol() === "symbol";
typeof Symbol("foo") === "symbol";
typeof Symbol.iterator === "symbol";
Перетворення символьного типу
Кілька речей, котрі слід мати на увазі при перетворенні типу символів.
- При спробі перетворити символ на число – викидається
TypeError
(наприклад,+sym
абоsym | 0
). - При застосуванні нестрогої рівності,
Object(sym) == sym
повертаєtrue
. Symbol("foo") + "bar"
викидаєTypeError
(не можна перетворювати символ на рядок). Це запобігає, наприклад, тихому створенню з символу нового рядкового імені властивості.- "безпечніше" перетворення
String(sym)
працює як викликSymbol.prototype.toString()
із символами, але зверніть увагу, щоnew String(sym)
викине помилку.
Символи та ітерація for...in
Символи не перелічуються при ітерації for...in
. Крім цього, Object.getOwnPropertyNames()
не поверне символьних властивостей об'єкта; проте можна застосувати Object.getOwnPropertySymbols()
для їх отримання.
const obj = {};
obj[Symbol("a")] = "a";
obj[Symbol.for("b")] = "b";
obj["c"] = "c";
obj.d = "d";
for (const i in obj) {
console.log(i);
}
// "c" "d"
Символи та JSON.stringify()
Властивості з символьними ключами геть ігноруються при використанні JSON.stringify()
:
JSON.stringify({ [Symbol("foo")]: "foo" });
// '{}'
Докладніше про це – JSON.stringify()
.
Об'єкти-обгортки Symbol як ключі властивостей
Коли об'єкт-обгортка Symbol використовується як ключ властивості, то такий об'єкт зводиться до загорнутого в ньому символу:
const sym = Symbol("foo");
const obj = { [sym]: 1 };
obj[sym]; // 1
obj[Object(sym)]; // все одно 1
Специфікації
Сумісність із браузерами
desktop | mobile | server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Symbol
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 36 | Internet Explorer No support Ні | Opera Full support 25 | Safari Full support 9 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 36 | Opera Android Full support 25 | Safari on iOS Full support 9 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
@@toPrimitive
|
Chrome Full support 47 | Edge Full support 15 | Firefox Full support 44 | Internet Explorer No support Ні | Opera Full support 34 | Safari Full support 10 | WebView Android Full support 47 | Chrome Android Full support 47 | Firefox for Android Full support 44 | Opera Android Full support 34 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.0.0 |
Symbol() constructor
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 36 | Internet Explorer No support Ні | Opera Full support 25 | Safari Full support 9 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 36 | Opera Android Full support 25 | Safari on iOS Full support 9 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
asyncIterator
|
Chrome Full support 63 | Edge Full support 79 | Firefox Full support 57 | Internet Explorer No support Ні | Opera Full support 50 | Safari Full support 11.1 | WebView Android Full support 63 | Chrome Android Full support 63 | Firefox for Android Full support 57 | Opera Android Full support 46 | Safari on iOS Full support 11.3 | Samsung Internet Full support 8.0 | Deno Full support 1.0 | Node.js Full support 10.0.0 |
description
|
Chrome Full support 70 | Edge Full support 79 | Firefox Full support 63 | Internet Explorer No support Ні | Opera Full support 57 | Safari Full support 12.1 | WebView Android Full support 70 | Chrome Android Full support 70 | Firefox for Android Full support 63 | Opera Android Full support 49 | Safari on iOS Full support 12.2 | Samsung Internet Full support 10.0 | Deno Full support 1.0 | Node.js Full support 11.0.0 |
for
|
Chrome Full support 40 | Edge Full support 12 | Firefox Full support 36 | Internet Explorer No support Ні | Opera Full support 27 | Safari Full support 9 | WebView Android Full support 40 | Chrome Android Full support 40 | Firefox for Android Full support 36 | Opera Android Full support 27 | Safari on iOS Full support 9 | Samsung Internet Full support 4.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
hasInstance
|
Chrome Full support 50 | Edge Full support 15 | Firefox Full support 50 | Internet Explorer No support Ні | Opera Full support 37 | Safari Full support 10 | WebView Android Full support 50 | Chrome Android Full support 50 | Firefox for Android Full support 50 | Opera Android Full support 37 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.5.0 |
isConcatSpreadable
|
Chrome Full support 48 | Edge Full support 15 | Firefox Full support 48 | Internet Explorer No support Ні | Opera Full support 35 | Safari Full support 10 | WebView Android Full support 48 | Chrome Android Full support 48 | Firefox for Android Full support 48 | Opera Android Full support 35 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.0.0 |
iterator
|
Chrome Full support 43 | Edge Full support 12 | Firefox Full support 36 | Internet Explorer No support Ні | Opera Full support 30 | Safari Full support 10 | WebView Android Full support 43 | Chrome Android Full support 43 | Firefox for Android Full support 36 | Opera Android Full support 30 | Safari on iOS Full support 10 | Samsung Internet Full support 4.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
keyFor
|
Chrome Full support 40 | Edge Full support 12 | Firefox Full support 36 | Internet Explorer No support Ні | Opera Full support 27 | Safari Full support 9 | WebView Android Full support 40 | Chrome Android Full support 40 | Firefox for Android Full support 36 | Opera Android Full support 27 | Safari on iOS Full support 9 | Samsung Internet Full support 4.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
match
|
Chrome Full support 50 | Edge Full support 79 | Firefox Full support 40 | Internet Explorer No support Ні | Opera Full support 37 | Safari Full support 10 | WebView Android Full support 50 | Chrome Android Full support 50 | Firefox for Android Full support 40 | Opera Android Full support 37 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.0.0 |
matchAll
|
Chrome Full support 73 | Edge Full support 79 | Firefox Full support 67 | Internet Explorer No support Ні | Opera Full support 60 | Safari Full support 13 | WebView Android Full support 73 | Chrome Android Full support 73 | Firefox for Android Full support 67 | Opera Android Full support 52 | Safari on iOS Full support 13 | Samsung Internet Full support 11.0 | Deno Full support 1.0 | Node.js Full support 12.0.0 |
replace
|
Chrome Full support 50 | Edge Full support 79 | Firefox Full support 49 | Internet Explorer No support Ні | Opera Full support 37 | Safari Full support 10 | WebView Android Full support 50 | Chrome Android Full support 50 | Firefox for Android Full support 49 | Opera Android Full support 37 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.0.0 |
search
|
Chrome Full support 50 | Edge Full support 79 | Firefox Full support 49 | Internet Explorer No support Ні | Opera Full support 37 | Safari Full support 10 | WebView Android Full support 50 | Chrome Android Full support 50 | Firefox for Android Full support 49 | Opera Android Full support 37 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.0.0 |
species
|
Chrome Full support 51 | Edge Full support 13 | Firefox Full support 41 | Internet Explorer No support Ні | Opera Full support 38 | Safari Full support 10 | WebView Android Full support 51 | Chrome Android Full support 51 | Firefox for Android Full support 41 | Opera Android Full support 41 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.5.0 |
split
|
Chrome Full support 50 | Edge Full support 79 | Firefox Full support 49 | Internet Explorer No support Ні | Opera Full support 37 | Safari Full support 10 | WebView Android Full support 50 | Chrome Android Full support 50 | Firefox for Android Full support 49 | Opera Android Full support 37 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.0.0 |
toPrimitive
|
Chrome Full support 47 | Edge Full support 15 | Firefox Full support 44 | Internet Explorer No support Ні | Opera Full support 34 | Safari Full support 10 | WebView Android Full support 47 | Chrome Android Full support 47 | Firefox for Android Full support 44 | Opera Android Full support 34 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.0.0 |
toSource
|
Chrome No support Ні | Edge No support Ні | Firefox No support 36 – 74 | Internet Explorer No support Ні | Opera No support Ні | Safari No support Ні | WebView Android No support Ні | Chrome Android No support Ні | Firefox for Android Full support 36 | Opera Android No support Ні | Safari on iOS No support Ні | Samsung Internet No support Ні | Deno No support Ні | Node.js No support Ні |
toString
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 36 | Internet Explorer No support Ні | Opera Full support 25 | Safari Full support 9 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 36 | Opera Android Full support 25 | Safari on iOS Full support 9 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
toStringTag
|
Chrome Full support 49 | Edge Full support 15 | Firefox Full support 51 | Internet Explorer No support Ні | Opera Full support 36 | Safari Full support 10 | WebView Android Full support 49 | Chrome Android Full support 49 | Firefox for Android Full support 51 | Opera Android Full support 36 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.0.0 |
toStringTag available on all DOM prototype objects
|
Chrome Full support 50 | Edge Full support 79 | Firefox Full support 78 | Internet Explorer No support Ні | Opera Full support 37 | Safari Full support 14 | WebView Android Full support 50 | Chrome Android Full support 50 | Firefox for Android Full support 79 | Opera Android Full support 37 | Safari on iOS Full support 14 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js No support Ні |
unscopables
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 48 | Internet Explorer No support Ні | Opera Full support 25 | Safari Full support 9 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 48 | Opera Android Full support 25 | Safari on iOS Full support 9 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
valueOf
|
Chrome Full support 38 | Edge Full support 12 | Firefox Full support 36 | Internet Explorer No support Ні | Opera Full support 25 | Safari Full support 9 | WebView Android Full support 38 | Chrome Android Full support 38 | Firefox for Android Full support 36 | Opera Android Full support 25 | Safari on iOS Full support 9 | Samsung Internet Full support 3.0 | Deno Full support 1.0 | Node.js Full support 0.12.0 |
Дивіться також
- Поліфіл
Symbol
у складіcore-js
typeof
- Типи даних і структури даних JavaScript
- Заглиблення в ES6: Символи на hacks.mozilla.org (2015)