JavaScript Symbol
A Symbol is a primitive data type introduced in ES6 that creates a guaranteed unique identifier. Every time a Symbol is created, it is unique — even if two symbols have the same description.
Symbols are mainly used as unique property keys on objects to avoid name collisions, and to define custom behavior through well-known symbols.
Creating a Symbol
let id1 = Symbol("id");
let id2 = Symbol("id");
console.log(id1 === id2); // false — always unique!
console.log(typeof id1); // symbol
console.log(id1.toString()); // Symbol(id)
console.log(id1.description); // idSymbols as Object Property Keys
Symbols are ideal for adding properties to objects without risk of overwriting existing keys — especially important when working with third-party objects or shared libraries.
let idKey = Symbol("id");
let roleKey = Symbol("role");
let user = {
name: "Ritika",
[idKey]: 101,
[roleKey]: "admin"
};
console.log(user.name); // Ritika
console.log(user[idKey]); // 101
console.log(user[roleKey]); // admin
// Symbol keys are NOT visible in regular object enumeration
console.log(Object.keys(user)); // ["name"]
console.log(Object.values(user)); // ["Ritika"]
console.log(JSON.stringify(user)); // {"name":"Ritika"} — symbols excludedSymbols Are Hidden in Iteration
Symbol-keyed properties are skipped by for...in, Object.keys(), and JSON.stringify(). This makes them useful for metadata that should not appear in normal object output.
let config = Symbol("config");
let app = {
name: "eStudy247",
version: "2.0",
[config]: { debug: true, maxUsers: 500 }
};
for (let key in app) {
console.log(key); // name, version — config symbol is hidden
}
// Access symbol properties explicitly
console.log(app[config].debug); // trueGetting Symbol Keys — Object.getOwnPropertySymbols()
let symbols = Object.getOwnPropertySymbols(app);
console.log(symbols); // [Symbol(config)]
console.log(app[symbols[0]]); // { debug: true, maxUsers: 500 }Global Symbol Registry — Symbol.for()
Normally, every Symbol() call creates a new unique symbol. Symbol.for() creates (or retrieves) a symbol in a global registry, allowing the same symbol to be shared across different parts of an application.
let s1 = Symbol.for("sharedKey");
let s2 = Symbol.for("sharedKey");
console.log(s1 === s2); // true — same symbol from registry
// Get the key of a registered symbol
console.log(Symbol.keyFor(s1)); // "sharedKey"Well-Known Symbols
JavaScript uses a set of built-in symbols (called well-known symbols) to allow objects to customize their behavior with built-in language operations.
Symbol.iterator — Custom Iteration
Defines how an object is iterated in a for...of loop.
let range = {
from: 1,
to: 5,
[Symbol.iterator]() {
let current = this.from;
let last = this.to;
return {
next() {
return current <= last
? { value: current++, done: false }
: { value: undefined, done: true };
}
};
}
};
for (let n of range) {
console.log(n); // 1, 2, 3, 4, 5
}Symbol.toPrimitive — Custom Type Conversion
Controls how an object is converted to a primitive value.
let temperature = {
celsius: 37,
[Symbol.toPrimitive](hint) {
if (hint === "number") return this.celsius;
if (hint === "string") return `${this.celsius}°C`;
return this.celsius;
}
};
console.log(+temperature); // 37 (number hint)
console.log(`Temp: ${temperature}`); // Temp: 37°C (string hint)
console.log(temperature + 0); // 37 (default hint)Symbol.hasInstance — Custom instanceof Behavior
class EvenNumber {
static [Symbol.hasInstance](num) {
return typeof num === "number" && num % 2 === 0;
}
}
console.log(4 instanceof EvenNumber); // true
console.log(7 instanceof EvenNumber); // falseSymbol.toStringTag — Custom Object Label
class Product {
get [Symbol.toStringTag]() {
return "Product";
}
}
let p = new Product();
console.log(Object.prototype.toString.call(p)); // [object Product]Symbol.species — Custom Return Type for Inherited Methods
class MyArray extends Array {
static get [Symbol.species]() {
return Array; // map/filter return plain Array, not MyArray
}
}
let arr = new MyArray(1, 2, 3);
let mapped = arr.map(x => x * 2);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // trueSymbol Use Cases Summary
| Use Case | Description |
|---|---|
| Unique property keys | Avoid naming conflicts in objects |
| Hidden metadata | Store internal data not visible in normal iteration |
| Library/framework hooks | Allow users to customize behavior without key conflicts |
| Custom iteration (Symbol.iterator) | Make any object work with for...of |
| Custom type conversion | Control how object converts to number/string |
Key Points to Remember
- A Symbol is always unique — two symbols with the same description are not equal
- Symbols are used as unique property keys to avoid naming collisions
- Symbol-keyed properties are hidden from
Object.keys(),for...in, andJSON.stringify() - Use
Object.getOwnPropertySymbols()to retrieve symbol-keyed properties Symbol.for(key)creates or retrieves a global shared symbol — useful across modules- Well-known symbols like
Symbol.iteratorandSymbol.toPrimitivecustomize built-in JavaScript behavior Symbol.iteratoris what makes objects compatible withfor...ofand spread syntax
