Symbol
This lesson explains Symbol with clear examples, use cases, and best practices so you can use modern JavaScript confidently in real projects.
ES6+ Symbol Overview
Symbol is a primitive data type introduced in ES6 that
creates unique and immutable identifiers. Every call to
Symbol() returns a new value, even if the description
text is the same.
Symbols are commonly used as special object property keys, hidden
metadata fields, and well-known hooks such as
Symbol.iterator. They help avoid naming collisions and
keep internal object behavior separate from normal string keys.
| Feature | Description |
| Introduced In | ES6 (ECMAScript 2015) |
| Type | Primitive value |
| Uniqueness | Every symbol is unique |
| Main Creation | Symbol(), Symbol.for() |
| Common Use | Unique object keys and internal metadata |
| Enumeration | Not included in for...in by default |
Basic Symbol Example
const id =
Symbol("userId");
const user = {
name: "Alex",
[id]: 101
};
console.log(user.name);
console.log(user[id]);
console.log(id.description);
Symbols can be used as object property keys with computed property
syntax. The description is optional and mainly useful for debugging.
How Symbol Works
A symbol value is always unique. Two symbols created separately are
never equal, even if they share the same description string.
| Step | Description | Example Syntax |
| Create Symbol | Generate a unique identifier. | Symbol("label") |
| Use as Key | Add property with computed syntax. | [symbolKey]: value |
| Access Value | Read property with the symbol reference. | obj[symbolKey] |
| Reuse Globally | Register symbol in global registry. | Symbol.for("app.id") |
| Lookup Key | Find registry key for a symbol. | Symbol.keyFor(symbol) |
| Inspect Symbols | Get symbol keys on an object. | Object.getOwnPropertySymbols(obj) |
Every Symbol Is Unique
const a =
Symbol("status");
const b =
Symbol("status");
console.log(a === b);
console.log(typeof a);
console.log(a.description);
The description "status" is only a label. It does not
make two symbols equal. This uniqueness is the main reason symbols
are useful as property keys.
Use Symbols as Object Keys
const roleKey =
Symbol("role");
const internalKey =
Symbol("internal");
const account = {
username: "alex",
[roleKey]: "admin",
[internalKey]: {
lastLogin: "2026-06-27"
}
};
console.log(account.username);
console.log(account[roleKey]);
console.log(account[internalKey]);
Symbol keys are useful when you want properties that should not
collide with regular string keys added by other code.
Global Symbols with Symbol.for()
const appIdA =
Symbol.for("app.id");
const appIdB =
Symbol.for("app.id");
console.log(appIdA === appIdB);
console.log(
Symbol.keyFor(appIdA)
);
Symbol.for() stores symbols in a global registry. If
the same key is requested again, JavaScript returns the existing
symbol instead of creating a new one.
Hidden-Like Object Properties
const secret =
Symbol("secret");
const config = {
theme: "dark",
[secret]: "internal-token"
};
for (const key in config) {
console.log(key, config[key]);
}
console.log(
Object.keys(config)
);
console.log(
Object.getOwnPropertySymbols(config)
);
Symbol properties do not appear in normal enumeration methods such
as for...in or Object.keys(). This makes
them useful for internal metadata, though they are not truly private.
Well-Known Symbols
| Symbol | Purpose |
Symbol.iterator | Defines default iteration behavior. |
Symbol.toStringTag | Customizes Object.prototype.toString output. |
Symbol.hasInstance | Customizes instanceof behavior. |
Symbol.toPrimitive | Controls object-to-primitive conversion. |
Symbol.species | Controls derived constructor behavior. |
Custom Iteration with Symbol.iterator
const range = {
start: 1,
end: 3,
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return {
next() {
if (current <= end) {
return {
value: current++,
done: false
};
}
return { done: true };
}
};
}
};
for (const value of range) {
console.log(value);
}
Well-known symbols let objects participate in built-in JavaScript
behavior. Symbol.iterator makes an object usable with
for...of.
Customize Object Identification
class Queue {
constructor() {
this.items = [];
}
}
Queue.prototype[Symbol.toStringTag] =
"Queue";
const queue = new Queue();
console.log(
Object.prototype.toString.call(queue)
);
console.log(queue.toString());
Symbol.toStringTag helps custom classes report a more
meaningful type name during debugging and inspection.
Common Symbol Methods and Properties
| Method / Property | Description | Example |
Symbol() | Creates a unique symbol. | Symbol("id") |
Symbol.for() | Gets or creates a global symbol. | Symbol.for("app") |
Symbol.keyFor() | Returns registry key for a global symbol. | Symbol.keyFor(sym) |
description | Readable label for debugging. | sym.description |
Object.getOwnPropertySymbols() | Lists symbol keys on an object. | Object.getOwnPropertySymbols(obj) |
Common Symbol Use Cases
- Creating unique object property keys.
- Avoiding naming collisions in shared objects.
- Storing internal metadata on objects.
- Defining custom iteration with
Symbol.iterator. - Customizing object behavior with well-known symbols.
- Building library internals that should not interfere with user keys.
Symbol Best Practices
- Use symbols when key uniqueness matters more than readability.
- Store the symbol reference in a variable or constant before using it as a key.
- Use
Symbol.for() only when global reuse is intentional. - Do not treat symbol properties as truly private security boundaries.
- Use descriptive symbol descriptions for easier debugging.
- Prefer well-known symbols when customizing built-in object behavior.
- Document symbol keys in libraries and frameworks.
Common Symbol Mistakes
- Assuming two symbols with the same description are equal.
- Trying to access a symbol property without keeping the symbol reference.
- Expecting symbol keys to appear in
Object.keys(). - Using
Symbol() when Symbol.for() global reuse is needed. - Believing symbol properties are completely private.
- Using symbols everywhere when string keys would be simpler.
- Forgetting that symbols cannot be created with
new Symbol().
Symbol Keys vs String Keys
| Feature | Symbol Key | String Key |
| Uniqueness | Always unique. | Can collide with other strings. |
| Enumeration | Hidden from normal loops. | Visible in for...in and Object.keys(). |
| Debugging | Uses description label. | Readable property name. |
| Best For | Internal metadata and custom hooks. | Normal object properties. |
Key Takeaways
- Symbol is a unique primitive type introduced in ES6.
- Use
Symbol() for unique keys and Symbol.for() for global symbols. - Symbol properties do not show up in normal object enumeration.
- Well-known symbols customize built-in JavaScript behavior.
- Symbols are great for metadata and collision-free keys, not for ordinary public properties.
Pro Tip
Keep symbol keys in module-level constants such as
const INTERNAL_ID = Symbol("internalId"). This makes
internal properties reusable without risking name collisions.