Symbol
The Symbol global object is the factory function that creates symbol values, and its static properties hold the well-known symbols that let objects customize built-in language behavior. Each value it returns is a symbol primitive, and Symbol.prototype supplies the methods those primitives call:
> const sessionKey = Symbol("session");
undefined
> sessionKey.description
'session'
> sessionKey.toString()
'Symbol(session)'
Symbol is an ECMAScript built-in added in ES2015. It’s Baseline Widely available, so it runs in every current browser and JavaScript runtime.
Syntax
The Symbol function takes one optional description:
Symbol([<description>])
| Parameter | Description |
|---|---|
description |
An optional value that’s converted to a string and stored as the symbol’s .description. It defaults to undefined |
The call returns a new, unique symbol primitive. The new keyword is forbidden, so new Symbol() throws a TypeError.
Key Static Methods and Properties
| Member | Kind | Description |
|---|---|---|
Symbol.for() |
Static method | Returns the symbol stored under a string key in the global symbol registry, creating it on first use |
Symbol.keyFor() |
Static method | Returns the registry key of a registered symbol, or undefined for any other symbol |
Symbol.iterator |
Static property | Names the method that makes an object iterable with for...of and spread syntax |
Symbol.asyncIterator |
Static property | Names the method that makes an object iterable with for await...of |
Symbol.toPrimitive |
Static property | Names the method that converts an object to a primitive value |
Symbol.toStringTag |
Static property | Names the property that Object.prototype.toString() reads for an object’s tag |
Symbol.hasInstance |
Static property | Names the method that customizes instanceof checks |
Symbol.dispose |
Static property | Names the cleanup method that using declarations and DisposableStack call. Stage 4 in 2026, expected in ES2027, and Baseline Limited availability |
Symbol.asyncDispose |
Static property | Names the async cleanup method that await using calls. Stage 4 in 2026, expected in ES2027, and Baseline Limited availability |
Other well-known symbols customize regular expressions and arrays: Symbol.match, Symbol.matchAll, Symbol.replace, Symbol.search, Symbol.split, Symbol.species, Symbol.isConcatSpreadable, and Symbol.unscopables.
Key Instance Methods and Properties
| Member | Kind | Description |
|---|---|---|
.description |
Instance property | Holds the description passed to Symbol(), or undefined when there was none |
.toString() |
Instance method | Returns a string in the form "Symbol(description)" |
.valueOf() |
Instance method | Returns the symbol primitive itself |
Examples
A Money class needs to behave like a number in arithmetic and like a formatted label in a template literal. A [Symbol.toPrimitive]() method receives a hint that tells it which form the operation wants:
> class Money {
… constructor(cents) {
… this.cents = cents;
… }
… [Symbol.toPrimitive](hint) {
… if (hint === "string") {
… return `$${(this.cents / 100).toFixed(2)}`;
… }
… return this.cents;
… }
… }
undefined
> const price = new Money(1999);
undefined
> price + 1
2000
> `Total: ${price}`
'Total: $19.99'
A paginated API client can expose its pages as an async iterable. Defining [Symbol.asyncIterator]() as an async generator method lets for await...of consume the pages one at a time:
> const feed = {
… async *[Symbol.asyncIterator]() {
… yield ["post-1", "post-2"];
… yield ["post-3"];
… },
… };
undefined
> for await (const page of feed) console.log(page);
[ 'post-1', 'post-2' ]
[ 'post-3' ]
undefined
A logging helper prints a type label for every value it receives. Setting [Symbol.toStringTag] on a class gives its instances a readable tag instead of the generic Object:
> class Connection {
… get [Symbol.toStringTag]() {
… return "Connection";
… }
… }
undefined
> Object.prototype.toString.call(new Connection())
'[object Connection]'
Common Gotchas
Calling Symbol with new throws, because symbols are primitives and the function isn’t a constructor:
> new Symbol("id")
Uncaught TypeError: Symbol is not a constructor
at new Symbol (<anonymous>)
Registered symbols from Symbol.for() can’t be keys in a WeakMap, because the registry keeps them alive forever. A symbol from Symbol() works:
> const cache = new WeakMap();
undefined
> cache.set(Symbol.for("user"), "Ada")
Uncaught TypeError: Invalid value used as weak map key
at WeakMap.set (<anonymous>)
> cache.set(Symbol("user"), "Ada").constructor.name
'WeakMap'
Non-registered symbols became valid weak keys in ES2023.
Have a question about this? Mentor AI can show you examples, compare related terms, and point you to tutorials.
By Leodanis Pozo Ramos • Updated Nov. 7, 2026