The global symbol registry is just a convenient global repository for symbol instances. You could implement one yourself if you wanted to, but having such a repository built-in means that the runtime can use it as a place to publish symbol instances that have particular meaning for a given context.
In your own application, you can decide that some types of objects will have certain properties accessible via some symbol. All your code can find those symbols via Symbol.for()
:
var SPECIAL_PROPERTY = Symbol.for("mySpecialProperty");
// ...
var specialVal = someObject[SPECIAL_PROPERTY];
Because the registry is global, that works regardless of scope or compilation unit.
By making the registry part of the runtime, an environment like Node.js can use the symbol mechanism to extend objects without fear of causing problems for legacy code. Like, if Node wanted to make it such that you could find out how much memory an object used, they could invent a symbol, put it in the registry, and document the registry key. Any code could then use that:
var objectSize = myObject[Symbol.for("memory_use")];
(That's totally made up; it might make no sense at all for Node to do that particular thing.) Because of the way symbols work as property keys, code that doesn't know about that won't experience any weird issues should the objects it manipulates suddenly start carrying around that extra property.
(Of course, the namespace of the symbol registry itself is just a namespace, so collisions would have to be dealt with there in pretty much exactly the same way we deal with name collisions in the window
object.)