← Back to Chapters

JavaScript Symbols

? JavaScript Symbols

⚡ Quick Overview

Symbols are a primitive data type introduced in ES6. They are unique and immutable values, mainly used as identifiers for object properties to avoid name collisions and create properties that are not accidentally overwritten.

Think of a symbol as a special kind of key that is guaranteed to be unique, even if it has the same description as another symbol.

? Key Concepts

  • Symbols are a primitive data type, like number, string, and boolean.
  • Every symbol value is unique, even if created with the same description.
  • Symbols are often used as object property keys to prevent name clashes.
  • The description passed to Symbol() is only for debugging/logging.
  • Well-known symbols (like Symbol.iterator) let you customize built-in behavior.
  • Symbol-keyed properties are not listed in normal enumeration methods like for...in.

? Syntax and Theory

To create a symbol, you call the Symbol() function:

Syntax

let mySymbol = Symbol(descriptionOptional);

  • Unique: Each call to Symbol() returns a new, unique symbol.
  • Immutable: Once created, a symbol's value cannot be changed.
  • Description: A string you pass for debugging, accessed via sym.description.

When used as object keys, symbols help create properties that will not clash with other keys, including those from libraries or other parts of your code.

? Code Examples

? Creating Unique Symbols

Even if two symbols share the same description, they are always different values.

? View Code Example
let sym1 = Symbol('description');
let sym2 = Symbol('description');

console.log(sym1 === sym2);
false (symbols are unique)

? Using Symbol Description

The description is useful in logs and debugging tools, but it does not affect equality.

? View Code Example
let sym = Symbol('id');
console.log(sym.description);
"id"

? Using Symbols as Object Keys

Symbols work great as “hidden” or non-colliding keys on objects. They do not appear in normal key enumeration but can still be accessed directly with the symbol.

? View Code Example
let id = Symbol('id');
let user = {
name: 'Alice',
[id]: 12345
};

console.log(user[id]);
12345
console.log(Object.keys(user));
["name"]
console.log(Object.getOwnPropertySymbols(user));
[Symbol(id)]

? Well-Known Symbols

JavaScript defines several built-in symbols (well-known symbols) that let you customize how objects behave with certain language features.

  • Symbol.iterator – Makes objects iterable (for for...of loops).
  • Symbol.toStringTag – Customizes Object.prototype.toString output.
  • Symbol.hasInstance – Customizes instanceof behavior.
? View Code Example
let obj = {
[Symbol.toStringTag]: 'CustomObject'
};

console.log(Object.prototype.toString.call(obj));
[object CustomObject]

? Live Output and Explanation

? What the Console Shows

  • Uniqueness example:
    • sym1 === sym2 prints false because each symbol is unique.
  • Description example:
    • sym.description prints the string passed to Symbol('id'), i.e., "id".
  • Object key example:
    • user[id] prints 12345 (the hidden property value).
    • Object.keys(user) prints ["name"], not including the symbol key.
    • Object.getOwnPropertySymbols(user) prints something like [Symbol(id)].
  • toStringTag example:
    • Object.prototype.toString.call(obj) prints [object CustomObject] instead of the default.

These outputs demonstrate that symbols provide unique, non-enumerable keys and can also customize how objects interact with core language features.

? Tips and Best Practices

  • Use symbols for “internal” or library-specific properties to avoid naming collisions.
  • Always store symbol references in variables/constants and reuse them to access the same property.
  • Remember that symbols do not show up in for...in or Object.keys(); use Object.getOwnPropertySymbols() when needed.
  • Use well-known symbols like Symbol.iterator and Symbol.toStringTag to customize interaction with built-in JavaScript features.
  • Do not rely on symbol descriptions for logic; they are purely for debugging and logging.

? Try It Yourself

  • Create two symbols with the same description and compare them using ===. Observe that they are not equal.
  • Add a symbol as a property key to an object and verify that it does not appear in Object.keys(), but it does appear in Object.getOwnPropertySymbols().
  • Implement a custom object with Symbol.iterator so you can iterate over it using a for...of loop.
  • Use Symbol.toStringTag on an object and check how Object.prototype.toString.call() output changes.