Символы — это относительно новый примитив, представленный в ES6. Примитив символа представляет собой уникальное значение, которое никогда не конфликтует ни с каким другим значением, включая значения других примитивов символов. Два строковых примитива, состоящих из одинаковых символов, оцениваются как строго равные:
String() === String()
> true
String( "My string." ) === String( "My string." );
> true
Однако никакие два символа, созданные с помощью функции Symbol()
не могут быть строго равными:
Symbol() === Symbol()
> false
Эта особенность позволяет использовать символы в качестве уникальных ключей свойств объекта, предотвращая конфликты с ключами, которые любой другой код может добавить к этому объекту.
const mySymbol = Symbol( "Desc" );
const myObject = {
}
myObject
> Object { Symbol("Desc"): "propSymbol" }
Существует три типа символов:
- Символы, созданные с помощью
Symbol()
- Общие символы, которые устанавливаются и извлекаются из глобального реестра символов с помощью
Symbol.for()
- «Общеизвестные символы» определяются как статические свойства объекта «Символ». Эти символы содержат внутренние методы, которые нельзя случайно перезаписать.
Symbol()
принимает описание (или «имя символа») в качестве необязательного аргумента. Эти описания представляют собой удобочитаемые метки для целей отладки и не влияют на уникальность результата. Любой вызов Symbol
возвращает совершенно уникальный примитив символа, даже если несколько вызовов имеют одинаковые описания:
Symbol( "My symbol." ) === Symbol( "My symbol." );
> false
Как и другие примитивные типы данных, символы наследуют методы и свойства от своего прототипа . Например, вы можете получить доступ к описанию как унаследованному свойству созданного символа:
let mySymbol = Symbol( "My symbol." );
mySymbol.description
> "My symbol."
Но вы не можете создать символ, используя new
ключевое слово:
let mySymbol = new Symbol();
> Uncaught TypeError: Symbol is not a constructor
Символы не являются перечисляемыми, то есть символические свойства недоступны при использовании стандартных методов для их перебора. Метод getOwnPropertySymbols()
предоставляет доступ к свойствам символа объекта.
Общие символы
Метод Symbol.for()
пытается найти любые существующие символы в глобальном реестре символов во время выполнения с заданной строкой в качестве ключа и возвращает соответствующий символ, если он найден. Если он его не находит, он создает символ с указанным ключом и добавляет его в глобальный реестр:
let sharedSymbol = Symbol.for( "My key." );
sharedSymbol === Symbol.for( "My key." )
> true
Эти ключи не имеют функционального дублирования с описаниями, присвоенными созданным автором примитивам Symbol
. Чтобы получить доступ к символу в реестре символов, вы должны сначала создать его с помощью for()
:
Symbol( "String" ) === Symbol( "String" );
> false
Symbol( "String" ) === Symbol().for( "String" );
> false
Symbol().for( "String" ) === Symbol().for( "String" );
> true
Чтобы получить ключ для любого символа из реестра символов, используйте Symbol.keyFor()
:
let mySymbol = Symbol.for( "Key." );
Symbol.keyFor( mySymbol ) ;
> "Key."
«Известные» символы
Хорошо известные символы — это статические свойства объекта Symbol
, каждое из которых само по себе является символом. Хорошо известные символы предоставляют уникальные ключи свойств для доступа и изменения встроенных методов JavaScript, предотвращая при этом непреднамеренную перезапись основного поведения.
Symbol;
> function Symbol()
asyncIterator: Symbol(Symbol.asyncIterator)
for: function for()
hasInstance: Symbol("Symbol.hasInstance")
isConcatSpreadable: Symbol("Symbol.isConcatSpreadable")
iterator: Symbol(Symbol.iterator)
keyFor: function keyFor()
length: 0
match: Symbol("Symbol.match")
matchAll: Symbol("Symbol.matchAll")
name: "Symbol"
prototype: Object { … }
replace: Symbol("Symbol.replace")
search: Symbol("Symbol.search")
species: Symbol("Symbol.species")
split: Symbol("Symbol.split")
toPrimitive: Symbol("Symbol.toPrimitive")
toStringTag: Symbol("Symbol.toStringTag")
unscopables: Symbol("Symbol.unscopables")
<prototype>: function ()
Поскольку символы являются функцией, специфичной для ES6, эти символические значения предназначены для использования в качестве «точек расширения» для разработчиков, изменяющих поведение JavaScript без возникновения проблем с обратной совместимостью.
Значения известных символов часто стилизуются с помощью префикса @@
или заключаются в %
, чтобы отличать их ключи от их изменяемых прототипов. Например, @@match
(или %match%
) — это ссылка на неизменяемый Symbol.match
, а не на String.prototype.match
.
Проверьте свое понимание
Можете ли вы использовать new
для создания символа?
Что из следующего описывает «хорошо известные» символы?