July 15, 2019 ☼ JS
The other day I was reading the source code of a LRU Cache implementation in Javascript and I noticed that the author was defining some variables using ES6 Symbols
:
const LENGTH_CALCULATOR = Symbol('lengthCalculator')
const ALLOW_STALE = Symbol('allowStale')
const MAX_AGE = Symbol('maxAge')
const DISPOSE = Symbol('dispose')
const NO_DISPOSE_ON_SET = Symbol('noDisposeOnSet')
I’ve never actually used them in production code and I was curious to find out more about their use cases and advantages over simple strings like const LENGTH_CALCULATOR = 'lengthCalculator'
for example.
Symbol
The data type symbol is a primitive data type. Every symbol value returned from
Symbol()
is unique. A symbol value may be used as an identifier for object properties; this is the data type’s only purpose.
Source: MDN
Mmm… ok. What does it actually mean? Why should I use them?
Let’s break down the definition:
A “primitive data type” in JS is a type of data that is not an Object
and doesn’t have any methods on its own. For example Number
, String
, and Boolean
are primitives.
1.toString()
// VM186:1 Uncaught SyntaxError: Invalid or unexpected token
Symbol()
is unique.Every time you create a new Symbol
it will hold a unique value. Without the reference to that Symbol
you won’t be able to use it and if you compare two Symbol
created with the same description they will never be equal.
const MAX_AGE = Symbol('maxAge');
const MAX_AGE_2 = Symbol('maxAge');
// If we try to log them out they seem to be equal
console.log(MAX_AGE) // Symbol(maxAge)
console.log(MAX_AGE_2) // Symbol(maxAge)
// But...
MAX_AGE === MAX_AGE_2 // false
This is probably the most common use case for Symbols. They can be assigned as Object
keys without worrying that these keys
will never create any conflict with the normal String keys or other Symbols.
Another advantage is that they won’t come up when you iterate over an object with the following methods:
for in
for of
Object.getOwnPropertyNames
The only way to access them is to use Object.getOwnPropertySymbols
.
const MAX_AGE = Symbol('maxAge');
const LRUCache = {};
LRUCache[MAX_AGE] = 0
console.log(LRUCache) // {Symbol(maxAge): 0}
// If I try to override the max age I simply can't
LRUCache['maxAge'] = 10;
console.log(LRUCache) // {maxAge: 10, Symbol(maxAge): 0}
Symbols allows you to create a hidden safe layer in your Objects.
There are quite a few that I can think of:
const align = {
LEFT: Symbol( 'LEFT' ),
RIGHT: Symbol( 'RIGHT' ),
UP: Symbol( 'UP' ),
DOWN: Symbol( 'DOWN' ),
}
React actually uses them to prevent XSS attack (assuming you have an existing server hole).
{
type: 'marquee',
props: {
bgcolor: '#ffa7c4',
children: 'hi',
},
key: null,
ref: null,
$$typeof: Symbol.for('react.element'),
}
Source: Why Do React Elements Have a $$typeof Property?
There are actually 3 types of Symbols
:
const FOO = Symbol('foo')
const FOO = Symbol.for('foo')
Symbol.asyncIterator
, Symbol.iterator
, Symbol.toPrimitive
etc.If you have any suggestions, questions, corrections or if you want to add anything please DM or tweet me: @zanonnicola