However, JSON knows only about lists and maps. There is no concept of object types or classes. This means that it is not easy to encode arbitrary objects, and some of the possible solutions are quite verbose (Encoding the type or class as a property and/or adding an indirection to encode the object's contents).
Adding a symbol (globally unique string) primitive type is a very useful addition: because symbols help to represent constant values in a compact and fast yet readable way, and because symbols allow simpler and more readable map keys.
In what way are ES6 “symbols” broken? (genuinely interested, I haven’t really used symbols before)
An ES6 symbol is a unique object with an optional name. They can be used as property names, like strings, which means that code can add new properties to objects without worrying about name collisions. Two symbols are distinct objects regardless of name: Symbol("foo") is never the same symbol as Symbol("foo").
Symbols as used in other languages (sometimes also called atoms) are effectively unique instances of strings. They chiefly serve the opposite purpose of ES6 symbols, which is being able to refer to the same object by name in different parts of code, even across executions of the program, or across distributed systems. i.e. :foo is always the same symbol as :foo.
They're (often) more efficient than simple strings because :foo and :foo will always reference the same object in a given instance of the program, so they can be compared by address rather than character-by-character.
Some languages with symbols have a function, often called gensym, for generating a symbol with a unique name, for when you need to support ES6's use case. e.g. Lisp and Prolog.
I've seen strawman proposals for ES to also support some form of a global symbol namespace, but after debugging much of the legacy of JS global-happy code and order-of-script-tags bugs I, for one, am happy that none of those strawman proposals are currently favored by the committee.