After getting a bad tooth pulled out, I called up the tooth fairy and asked her for an exact replacement. "Well, I can give you a new tooth but it won't be an exact copy of the one you lost", she said. "But why's that??", I was upset but curious. "That's one of the many rules we follow in the fairyland, sorry but no duplicates". I got excited, an idea struck my mind. I called up her sister, the Symbol fairy. "Hey!", I said. "Do you also never provide duplicates like your fairy sister"? I mean I have a list of stuff to which I need to allocate IDs, they must be all different in some way or the other. Now every other time I make a wish, she flares her wand in the air and gives me an unique symbol that never ever existed in this world and can never be duplicated.
2 - She has a wand (the constructor of the Symbol object)
3 - To make a wish you just say Symbol() or you can add your own description to the wish Symbol("some_key"), that doesn't make much difference. No matter how many times you make the same wish you will get a different symbol.
5 - Symbol fairy has a secret, if you ask for your wish like this - Symbol.for("some_key") ,she stores all the symbols you asked for, in the fairyland (Global Symbol Registry) and you can get the same Symbol again by calling Symbol.for("some_key") anytime. Don't worry this does not break the rule of duplicates. You just keep getting the same symbol that's stored for you in the Global Symbol Registry for some purpose.
Alright let's come back to life and discuss Symbols quickly. We now know that Symbols are nothing but unique values returned when we make a call to the constructor of the inbuilt Symbol object. Symbol('myKey') != Symbol('yourKey') and unsurprisingly Symbol('myKey') != Symbol('myKey'). Every Symbol() call is guaranteed to return a unique Symbol. We also know that by simply saying Symbol.for('myKey') we create a Symbol in the Global Registry and if it was already created earlier, you get access to the same old Symbol. Nothing complicated!
Even though the use-cases are trim, let us also discuss situations where you may want to use Symbols:
1 - Symbols as property names in an Object - You want unique property names when dealing with an object that may be manipulated by different sections of application code? Now you know you have a better alternative than using string keys. Wait! there's a catch, you cannot do this for any object property in general. The catch is, if you assign a Symbol as a property key within your object, the for...in loop will simply not detect it. This doesn't mean full encapsulation of the property ( there are other ways to reveal it ) but it will be of no use when you want to keep the property enumerable, which we normally do. So when do we bring in Symbols? You guessed it, when we want a particular property to have an unique (non-clashing) name and want to keep it hidden from the for...in loop as well.
2 - Symbols as a replacement to String and Number constants - Sometimes you'd like to use constants in your code. For example lets consider a situation where you want to apply some settings to your application based on the screen size on which it gets rendered. You can obviously use the evergreen if/else ladder or go by the switch/case block but that's not our concern. What would you use to identify different screen sizes, strings? numbers? Well, we have Symbols now. Lets talk with an example to avoid unnecessary confusion.
You could have used strings and numbers to identify screen sizes like xs = 0, md = 1 and so on but using symbols definitely gives you a fine grain control. Now you cannot simply say - new Settings(0) - and neither can you say - new Settings(Symbol('xs')). Such things can be more useful while debugging. Instead of seeing number and string values in the log, you can be more confident with Symbols. This may not be the best example but you get the gist.
Symbols may not be something that you would want to use as a daily thing while you code but again for the same reason many programmers keep them off their eyes. They are as simple to understand as any other primitive data type is. Remember the most common use cases we discussed and you shall know when you really need to meet the Symbol fairy.