Symbols - jellyfish-tom/TIL GitHub Wiki
[SOURCES]
- https://www.keithcirkel.co.uk/metaprogramming-in-es6-symbols/
- http://exploringjs.com/es6/ch_symbols.html
Symbols are a new primitive. Just like the Number, String, and Boolean primitives, Symbols have a Symbol function which can be used to create them. Unlike the other primitives, Symbols do not have a literal syntax (e.g how Strings have '') - the only way to make them is with the Symbol constructor-not-constructor-thingy.
Symbol(); // symbol
console.log(Symbol()); // prints "Symbol()" to the console
assert(typeof Symbol() === 'symbol')
new Symbol(); // TypeError: Symbol is not a constructor
Symbols can be given a description, which is really just used for debugging to make life a little easier when logging them to a console:
console.log(Symbol('foo')); // prints "Symbol(foo)" to the console.
assert(Symbol('foo').toString() === 'Symbol(foo)');
- each new Symbol has a completely unique value (even having same description)
- Symbols do not show up on an
Objectusingfor in,for oforObject.getOwnPropertyNames. The only way to get the Symbols within anObjectisObject.getOwnPropertySymbols Symbol.for(). This method creates a Symbol in a “global Symbol registry”. This registry is also cross-realm, meaning a Symbol from an iframe or service worker will be the same as one generated from your existing frame.
Having global Symbols does make things more complicated, but for good reason, which we’ll get to. Right now some of you are probably saying “Argh!? How will I know which Symbols are unique Symbols and which Symbols aren’t?”,
Symbol.keyFor()checks if key for givenSymbolexists in global registry. If it does, symbol has been created withSymbol.for()if it doesnt, than it s not globalSymbol, hence it was created usingconstructor-not-constructormethod -Symbol()(so calledfactory)
Well Known Symbols
A key part of what makes Symbols useful, is a set of Symbol constants, known as “well known symbols”.
These are effectively a bunch of static properties on the Symbol class which are implemented within other native objects, such as Arrays, Strings, and within the internals of the JavaScript engine.
In human words: in your custom classes you can provide your own implementation that will work when used with Javascript native methods. Below methods/operators are implementable:
Beware! Implementation of each vary from another, so always check how to implement one you want.
- Symbol.hasInstance
- Symbol.iterator
- Symbol.isConcatSpreadable
- Symbol.unscopables
- Symbol.match
- Symbol.replace
- Symbol.search
- Symbol.split
- Symbol.species
- Symbol.toPrimitive
- Symbol.toStringTag
What are Symbols good for
-
As a unique value where you’d probably normally use a String or Integer. Basically object key that will for sure be unique. (useful every time you work with shared objects, that are accessed by different clients and may already have properties you want to set on them, or will get iterated and adding anything may break some behaviors)
-
A place to put metadata values in an Object (just remember, things stored under key made with
Symbolwill not be private. So any other code can access/overwrite them by mistake)
Additional info
The following operations are aware of symbols as property keys:
Reflect.ownKeys()Property access via []Object.assign()
The following operations ignore symbols as property keys:
Object.keys()Object.getOwnPropertyNames()for-in loop
Symbols can't be coerced to strings. Coercing (implicitly converting) symbols to strings throws exceptions:
const sym = Symbol('desc');
const str1 = '' + sym; // TypeError
const str2 = `${sym}`; // TypeError
The only solution is to convert explicitly:
const str2 = String(sym); // 'Symbol(desc)'
const str3 = sym.toString(); // 'Symbol(desc)'