Symbol()
Creates a unique primitive value usable as a collision-free property key.
Symbol()
Symbol(description)- Added in JavaScript ES2015
Parameters
| Parameter | Type | Description |
|---|---|---|
$descriptionoptional | string | A label used only for debugging output. It has no effect on the symbol's identity. |
Return value
symbolA new unique symbol primitive. Two calls never produce equal symbols, even with the same description.
Errors
Throws a TypeError when called with new, because Symbol is not a constructor.
Symbol() mints a brand-new primitive every time it is called. The description is a debugging label and nothing more: Symbol("id") === Symbol("id") is false, and there is no way to look a symbol up by its description. That uniqueness is the whole feature.
When to reach for it
Use a symbol when you need to hang data on an object that you do not own. Because the key is a value only your module holds a reference to, no library and no future version of that object's shape can collide with it.
Symbol-keyed properties are skipped by Object.keys(), for...in and JSON.stringify(). They are reachable only through Object.getOwnPropertySymbols() and Reflect.ownKeys().
What trips people up
Symbols are not private — they are merely hard to guess, and Object.getOwnPropertySymbols() hands them to anyone. Use #private class fields for real encapsulation. They are also not shared across realms or module instances; when two copies of your code must agree on the same key, use Symbol.for() instead.
Example
When to use it
- Tag third-party objects with your own metadata without risking a name clash
- Store cached or derived state on an object so it stays out of JSON output
- Define a protocol method (like a custom iterator) that ordinary key enumeration ignores
Frequently asked questions
Why does Symbol('a') === Symbol('a') return false?
Because every call to Symbol() creates a new unique value, and the description is only a debug label. If you want the same symbol back for the same key, use Symbol.for('a') instead.
Are symbol properties private?
No. Symbol keys are hidden from Object.keys(), for...in and JSON.stringify(), but Object.getOwnPropertySymbols() and Reflect.ownKeys() expose them to any code that can reach the object. Use #private class fields for genuine privacy.
Why can't I use new Symbol()?
Symbol is a function, not a constructor, so new Symbol() throws a TypeError. Call Symbol() directly, and use Object(sym) if you specifically need a wrapper object.
More examples
Symbol is not a constructor
The output shows the TypeError raised by new Symbol(), then that Object(sym) is the supported way to obtain a wrapper object — typeof reports "object" for the wrapper and "symbol" for the primitive it holds.
try {
new Symbol("nope");
} catch (err) {
console.log(err.constructor.name);
console.log(err instanceof TypeError);
}
// To get a wrapper object, coerce an existing symbol instead:
const wrapped = Object(Symbol("ok"));
console.log(typeof wrapped);
console.log(typeof wrapped.valueOf());Non-colliding metadata on a shared object
The symbol key and the string key "cache" coexist on the same object. Object.entries() sees only the string keys, while Reflect.ownKeys() lists both.
const CACHE = Symbol("cache");
const config = { name: "cache", retries: 3 };
config[CACHE] = { hits: 0 };
config[CACHE].hits++;
console.log(config.cache); // untouched string key
console.log(config[CACHE].hits);
console.log(Object.entries(config));
console.log(Reflect.ownKeys(config).map(String));
Discussion