Skip to content

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.