Skip to content
FLAVIO COPES
flaviocopes.com
2026

JavaScript Symbols

By

Learn how JavaScript Symbol values create unique property keys, how the global symbol registry works, and why symbol properties are not private.

~~~

A Symbol is a JavaScript primitive value used as a unique identity. Calling Symbol() creates a new one.

Symbols are mainly used as object property keys. They let libraries add properties without colliding with string keys chosen by other code.

Create a Symbol

Call Symbol():

const id = Symbol()

Do not use new Symbol(). Symbol is not a constructor.

Every call creates a different value:

Symbol() === Symbol() //false

You can add a description:

const id = Symbol('id')

console.log(id.description) //'id'
console.log(id) //Symbol(id)

The description helps with debugging. It does not change the symbol’s identity:

Symbol('id') === Symbol('id') //false

Use Symbols as property keys

Use square brackets for a symbol key:

const id = Symbol('id')

const person = {
  name: 'Flavio',
  [id]: 42,
}

console.log(person[id]) //42

The Symbol key cannot collide with the string key 'id':

person.id = 'public-id'

console.log(person.id) //'public-id'
console.log(person[id]) //42

This is useful when different libraries add metadata to the same object.

Symbol properties are not private

Symbol keys are less visible than string keys, but they are not private or secret.

Object.keys() and Object.getOwnPropertyNames() skip them:

console.log(Object.keys(person)) //['name', 'id']

for...in and JSON.stringify() skip Symbol-keyed properties too.

But code can still discover them:

console.log(Object.getOwnPropertySymbols(person)) //[Symbol(id)]
console.log(Reflect.ownKeys(person)) //['name', 'id', Symbol(id)]

Use private class fields or closures when you need encapsulation. Never use a Symbol to protect sensitive data.

Share a Symbol with Symbol.for

Symbol.for() uses the global symbol registry:

const first = Symbol.for('app.user-id')
const second = Symbol.for('app.user-id')

console.log(first === second) //true

This is different from Symbol(), which always creates a new value.

Get a registered Symbol’s key with Symbol.keyFor():

console.log(Symbol.keyFor(first)) //'app.user-id'

Symbol.keyFor() returns undefined for a Symbol that is not in the registry.

Use a specific, namespaced registry key. A generic key such as 'id' can collide with unrelated code that uses the same registry.

Well-known Symbols

JavaScript defines well-known Symbols that let objects participate in language features.

For example, Symbol.iterator defines how for...of reads values:

const countdown = {
  *[Symbol.iterator]() {
    yield 3
    yield 2
    yield 1
  },
}

console.log([...countdown]) //[3, 2, 1]

Other well-known Symbols customize operations such as string matching, type conversion, and instanceof.

Most application code does not need to create these protocols. You will see them more often in libraries and built-in objects.

See the MDN references for Symbol, Symbol.for(), and Object.getOwnPropertySymbols().

~~~

Related posts about js: