Symbols
In your class, there might be two students named "Rahul Sharma". 👥
Same name, but they are different people. How does the school tell them apart? Each student has a unique roll number or Aadhaar number. Even if the names match, the numbers never do.
JavaScript has a special value that works just like that unique number. It is called a Symbol.
What Is a Symbol?
📝 Definition: A Symbol is a primitive data type in JavaScript that represents a unique and unchangeable value. Every Symbol you create is different from every other Symbol, even if they have the same description.
Symbols were added to JavaScript in ES6 (2015). It is one of the 7 primitive data types:
Key points to remember 📌
- A Symbol is always unique. No two Symbols are ever equal.
- A Symbol is a primitive, not an object.
- Its main use is as a special object key that never clashes with other keys.
- Symbol keys are hidden from normal loops and
Object.keys().
Why Do We Need Symbols?
Imagine you're working on a big project with many developers. 👨💻👩💻 Everyone adds properties to the same user object.
Normal string keys can clash by accident. 💥
Now with a Symbol key, there is no clash:
Both "id" values live happily together, because a Symbol key is unique. 🤝
Creating a Symbol
Use the Symbol() function.
const mySymbol = Symbol();
const id = Symbol("id"); // with a description
The description
The text inside Symbol("...") is called the description. It's just a label to help you when debugging. It does not make the symbol unique, and it does not affect the value.
⚠️ Don't use new with Symbol
Symbol() is a function that returns a primitive, not a constructor that builds an object. So always write Symbol(), not new Symbol().
Symbols Are Always Unique
This is the most important thing about Symbols.
Compare this with strings:
Using Symbols as Object Keys
To use a Symbol as a key, put it in square brackets [ ]. This is a computed property.
⚠️ Always use bracket notation
obj[symbol]to read a symbol key. Dot notationobj.symbollooks for a normal string key instead.
Adding a symbol key later
Symbol Keys Are Hidden 🙈
Symbol keys don't show up in the usual places. This makes them great for "behind-the-scenes" data.
| Place | Shows symbol keys? |
|---|---|
for...in loop | ❌ No |
Object.keys() / values() / entries() | ❌ No |
JSON.stringify() | ❌ No |
obj[symbol] | ✅ Yes |
Object.getOwnPropertySymbols() | ✅ Yes |
Reflect.ownKeys() | ✅ Yes (all keys) |
Finding symbol keys
🔐 Hidden is not the same as private! Anyone can still find symbol keys using
Object.getOwnPropertySymbols(). Symbols help avoid accidents. They are not a security feature.
Copying keeps symbol keys
The spread operator ... and Object.assign() do copy symbol keys.
Global Symbols: Symbol.for()
Sometimes you want to share the same symbol in different parts of your app. For that, JavaScript keeps a global symbol registry, like a common notice board 📋 that everyone can read.
Symbol.for("key"):
- looks for a symbol with that key in the registry
- if it exists, returns it
- if not, creates a new one and saves it
Symbol.keyFor()
Gets the key name of a global symbol.
Symbol() vs Symbol.for()
| Point | Symbol("x") | Symbol.for("x") |
|---|---|---|
| Creates a new symbol every time? | ✅ Yes | ❌ No, reuses it if it exists |
| Two calls equal? | ❌ Never | ✅ Yes |
| Stored in the global registry? | ❌ No | ✅ Yes |
Symbol.keyFor() works? | ❌ No | ✅ Yes |
Symbols Can't Be Auto-Converted to Text
Symbols refuse to be automatically turned into strings or numbers. This prevents accidental mistakes.
Real-Life Use Cases
1. Unique constants (instead of plain strings)
When you need fixed options that should never be confused with normal text, use Symbols.
A random string like "shipped" can't accidentally match. Only the real symbol works. 🎯
2. Adding safe extra data to objects
Add your own information to an object from someone else's code, without the risk of overwriting their properties.
3. Customising built-in behaviour (well-known symbols)
JavaScript has some built-in symbols that let you change how your objects behave. Let's look at them next!
Well-Known Symbols
JavaScript has built-in symbols, called well-known symbols, that control how objects work behind the scenes. You write them like Symbol.name.
| Symbol | What it controls |
|---|---|
Symbol.iterator | How for...of and spread ... go through your object |
Symbol.toPrimitive | What happens when your object is turned into a number or string |
Symbol.toStringTag | The name shown by Object.prototype.toString() |
Symbol.asyncIterator | How for await...of works (advanced) |
Symbol.iterator: make your object work with for...of
Normally, a plain object can't be used with for...of.
But if you add a Symbol.iterator method, it can!
The
*andyieldmake this a generator function. You will learn generators in a later lesson. For now, just see howSymbol.iteratormakesfor...ofwork.
Symbol.toPrimitive: control conversion
Symbol.toStringTag: a custom type name
💡 Well-known symbols are advanced. As a beginner, just remember that
Symbol.iteratoris what makes arrays, strings, Maps, and Sets work withfor...of.
Common Mistakes to Avoid
| Mistake | Problem | Fix |
|---|---|---|
new Symbol("id") | ❌ TypeError: not a constructor | Use Symbol("id") |
Expecting Symbol("a") === Symbol("a") | Always false | Store the symbol in a variable and reuse it, or use Symbol.for() |
Reading with obj.mySymbol | Gets undefined | Use obj[mySymbol] |
"Text " + symbol | ❌ TypeError | Use symbol.toString() or symbol.description |
Expecting symbol keys in Object.keys() or JSON | They are hidden | Use Object.getOwnPropertySymbols() |
| Using symbols to hide secrets | Anyone can still find them | Use real private fields (#secret) in classes |
| Losing the symbol variable | You can't read the value easily anymore | Keep a reference to the symbol |
Quick Summary Table
| Task | Code |
|---|---|
| Create a symbol | const id = Symbol("id"); |
| Read its description | id.description |
| Use it as a key | const obj = { [id]: 123 }; |
| Read a symbol key | obj[id] |
| Find all symbol keys | Object.getOwnPropertySymbols(obj) |
| Get or create a global symbol | Symbol.for("appId") |
| Get a global symbol's key | Symbol.keyFor(sym) |
| Convert to text | id.toString() |
| Check the type | typeof id === "symbol" |
| Make an object iterable | [Symbol.iterator]() { ... } |
Key Takeaways
- A Symbol is a primitive data type that is always unique.
Symbol("id") === Symbol("id")isfalse. - The text in
Symbol("...")is only a description for debugging. It doesn't affect uniqueness. - Symbols are mainly used as object keys that never clash. Read them with bracket notation
obj[sym]. - Symbol keys are hidden from
for...in,Object.keys(), andJSON.stringify(), but they are not truly private. - Use
Symbol.for()to share one symbol across your app, and well-known symbols likeSymbol.iteratorto customise how JavaScript works with your objects.