Uma primitiva de símbolo representa um valor exclusivo que nunca colide com nenhum outro valor, incluindo o valor de outras primitivas de símbolo. Duas primitivas de string compostas de caracteres idênticos são avaliadas como estritamente iguais:
String() === String()
> true
String( "My string." ) === String( "My string." );
> true
No entanto, nenhum símbolo criado usando a função Symbol()
pode ser
estritamente igual:
Symbol() === Symbol()
> false
Essa característica permite usar símbolos como chaves de propriedade exclusivas em um objeto, evitando colisões com chaves que qualquer outro código possa adicionar a esse objeto.
const mySymbol = Symbol( "Desc" );
const myObject = {};
myObject[mySymbol] = "propSymbol";
myObject
> Object { Symbol("Desc"): "propSymbol" }
Há três tipos de símbolos:
- Símbolos criados com
Symbol()
- Símbolos compartilhados que são definidos e recuperados de um registro de símbolos global usando
Symbol.for()
- "Símbolos conhecidos" definidos como propriedades estáticas no objeto Symbol. Esses símbolos contêm métodos internos que não podem ser substituídos acidentalmente.
Symbol()
aceita uma descrição (ou "nome do símbolo") como um argumento opcional.
Essas descrições são rótulos legíveis por humanos para fins de depuração e
não afetam a exclusividade do resultado. Qualquer chamada para Symbol
retorna uma
primitiva de símbolo completamente exclusiva, mesmo que várias chamadas tenham descrições
idênticas:
Symbol( "My symbol." ) === Symbol( "My symbol." );
> false
Assim como outros tipos de dados primitivos, os símbolos herdam métodos e propriedades do protótipo. Por exemplo, é possível acessar uma descrição como uma propriedade herdada do símbolo criado:
let mySymbol = Symbol( "My symbol." );
mySymbol.description
> "My symbol."
Mas não é possível criar um símbolo usando a palavra-chave new
:
let mySymbol = new Symbol();
> Uncaught TypeError: Symbol is not a constructor
Os símbolos não são enumeráveis, ou seja, as propriedades simbólicas não estão disponíveis
ao usar métodos padrão para iterar sobre elas. O método getOwnPropertySymbols()
dá acesso às propriedades de símbolo de um objeto.
Símbolos compartilhados
O método Symbol.for()
tenta procurar todos os símbolos em um
registro de símbolos global em tempo de execução com uma string específica como chave e retorna
o símbolo correspondente, se encontrado. Se ele não encontrar um, ele vai criar um símbolo
com a chave especificada e adicioná-lo ao registro global:
let sharedSymbol = Symbol.for( "My key." );
sharedSymbol === Symbol.for( "My key." )
> true
Essas chaves não têm sobreposição funcional com as descrições atribuídas às
primitivas Symbol
criadas pelo autor. Para acessar um símbolo no registro de símbolos,
primeiro crie-o usando for()
:
Symbol( "String" ) === Symbol( "String" );
> false
Symbol( "String" ) === Symbol.for( "String" );
> false
Symbol.for( "String" ) === Symbol.for( "String" );
> true
Para recuperar a chave de qualquer símbolo do registro de símbolos, use
Symbol.keyFor()
:
let mySymbol = Symbol.for( "Key." );
Symbol.keyFor( mySymbol ) ;
> "Key."
Símbolos "conhecidos"
Os símbolos conhecidos são propriedades estáticas do objeto Symbol
, e cada um deles
é um símbolo. Símbolos conhecidos fornecem chaves de propriedade exclusivas para
acessar e modificar os métodos integrados do JavaScript, evitando que o comportamento
principal seja substituído acidentalmente.
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 ()
Como os símbolos são um recurso específico do ES6, esses valores simbólicos são usados como "pontos de extensão" para que os desenvolvedores modifiquem o comportamento do JavaScript sem introduzir problemas de compatibilidade com versões anteriores.
Os valores de símbolos conhecidos geralmente são estilizados com um
prefixo @@
ou envoltos em %
para
diferenciar as chaves dos protótipos mutáveis. Por exemplo, @@match
(ou %match%
) é uma referência ao Symbol.match
imutável, não
String.prototype.match
.
Teste seu conhecimento
É possível usar new
para criar um símbolo?
Qual das opções a seguir descreve símbolos "conhecidos"?