Suggest an editImprove this articleRefine the answer for “The Symbol type in JavaScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`Symbol` is a primitive type whose value is unique and immutable, and it can be used as an object property key.** Two symbols with the same description are never equal: `Symbol('id') === Symbol('id')` returns `false`. Symbol keys do not show up in `for...in`, `Object.keys()` or `JSON.stringify()`, which makes them a good fit for "hidden" internal data that will not clash with someone else's code; you read them with `Object.getOwnPropertySymbols()`. The global registry `Symbol.for(key)` returns the same symbol across different parts of a program, and well known symbols such as `Symbol.iterator` let you change how objects behave. ```javascript const id = Symbol('id'); const user = { name: 'Alex', [id]: 123 }; console.log(user[id], Object.keys(user)); // 123 ['name'] ``` **Key point:** `Symbol` is a unique identifier for property keys that stays invisible to ordinary object enumeration.Shown above the full answer for quick recall.Answer (EN)Image**`Symbol` is a unique and immutable value that can be used as an object property key.** Every `Symbol` is unique, even when its description is identical to another symbol's. ## Theory ### TL;DR - `Symbol` is a primitive type, alongside `string`, `number`, `boolean` and the others. - Every call to `Symbol('id')` creates a new unique value. - A symbol can be used as a property key: `{ [sym]: value }`. - Symbol keys are invisible to `for...in`, `Object.keys()` and `JSON.stringify()`. - You read them with `Object.getOwnPropertySymbols()`. - `Symbol.for()` gives a shared global symbol, `Symbol.keyFor()` returns its name. - Well known symbols (`Symbol.iterator`, `Symbol.toPrimitive` and others) change how objects behave. ### Quick example ```javascript const id1 = Symbol('id'); const id2 = Symbol('id'); console.log(id1 === id2); // false ``` Despite the identical description `'id'`, the symbols are not equal. Every `Symbol` is a unique identifier, and the description exists only for debugging convenience. ### Why Symbol exists Before symbols, object property keys could only be strings. Sometimes you need to add a "hidden" property to an object so that it does not disturb the rest of the code, for example third party libraries. That is exactly where `Symbol` helps. ```javascript const id = Symbol('id'); const user = { name: 'Alex', [id]: 123, // a symbol as the key }; console.log(user); // { name: 'Alex', [Symbol(id)]: 123 } console.log(user[id]); // 123 console.log(Object.keys(user)); // ['name'], the symbol is not listed ``` Symbol keys take no part in `for...in` or `Object.keys()` and do not clash with other properties. That is handy for internal data or "private" properties. ```javascript const TOKEN = Symbol('token'); const session = { user: 'Tim', [TOKEN]: 'secret-token-123', }; console.log(session.user); // Tim console.log(session[TOKEN]); // secret-token-123 console.log(Object.keys(session)); // ['user'] ``` In other words, the `[TOKEN]` property does exist, but it is "invisible" to most operations. There is a dedicated method for reading symbol properties: ```javascript const symbols = Object.getOwnPropertySymbols(session); console.log(symbols); // [Symbol(token)] console.log(session[symbols[0]]); // secret-token-123 ``` `Symbol` compared with other types used as keys: | Type | Can be an object key | Unique | Appears in `for...in` | | --- | --- | --- | --- | | `string` | Yes | No | Yes | | `number` | No, it is converted to a string | No | Yes, as a string | | `Symbol` | Yes | Yes | No | ### A Symbol is never coerced to a string implicitly ```javascript const sym = Symbol('id'); console.log('My symbol: ' + sym); // TypeError ``` To print a symbol as a string, do it explicitly: ```javascript console.log(sym.toString()); // Symbol(id) console.log(String(sym)); // Symbol(id) console.log(sym.description); // id ``` ### Global symbols: Symbol.for and Symbol.keyFor Sometimes the very same `Symbol` has to be used in different parts of a program. The global symbol registry exists for that: ```javascript const a = Symbol.for('shared'); const b = Symbol.for('shared'); console.log(a === b); // true ``` - `Symbol.for(key)` creates a new global symbol or returns the existing one. - `Symbol.keyFor(sym)` returns the name the symbol is registered under: ```javascript console.log(Symbol.keyFor(a)); // 'shared' ``` For an ordinary `Symbol('id')` created outside the registry, `Symbol.keyFor()` returns `undefined`. ### Well known symbols JavaScript defines several built in symbols that let you override how objects behave: | Symbol | What it is used for | | --- | --- | | `Symbol.iterator` | Makes an object iterable (`for...of`) | | `Symbol.toPrimitive` | Controls conversion of an object to a primitive | | `Symbol.toStringTag` | Defines the name used by `Object.prototype.toString` | | `Symbol.hasInstance` | Defines the behaviour of the `instanceof` operator | | `Symbol.species` | Controls the constructor used for derived objects | | `Symbol.asyncIterator` | For asynchronous iterators | A `Symbol.iterator` example: ```javascript const numbers = { data: [1, 2, 3], [Symbol.iterator]() { let i = 0; const arr = this.data; return { next() { return i < arr.length ? { value: arr[i++], done: false } : { done: true }; } }; } }; for (const n of numbers) { console.log(n); // 1, 2, 3 } ``` Thanks to `Symbol.iterator`, a plain object became iterable. ### When to use it in practice Use `Symbol` when: - you need a unique identifier that will not collide with other properties; - you want to add a "private" property to an object or a class; - you want to tune object behaviour through well known symbols (`Symbol.iterator`, `Symbol.toPrimitive` and so on). Short summary: | What | Description | | --- | --- | | **Type** | Primitive (`symbol`) | | **Main trait** | Uniqueness | | **Creation** | `Symbol('description')` | | **Object keys** | Can serve as a key, unique and hidden | | **Global symbols** | `Symbol.for()` and `Symbol.keyFor()` | | **Well known symbols** | Let you override JS behaviour | ### Common mistakes - **Calling `Symbol` with `new`.** `new Symbol('id')` throws a `TypeError`: it is a primitive, not a constructor. - **Comparing symbols by description.** `Symbol('id') === Symbol('id')` is always `false`; only `Symbol.for('id')` gives a shared symbol. - **Concatenating a symbol with a string implicitly.** `'x' + sym` throws a `TypeError`, you need an explicit `String(sym)` or `sym.toString()`. - **Treating symbol properties as truly private.** They are only hidden from ordinary enumeration, while `Object.getOwnPropertySymbols()` and `Reflect.ownKeys()` reveal them. - **Expecting symbol keys in JSON.** `JSON.stringify()` silently drops them, so data that must be serialised should not be hidden behind a symbol. - **Forgetting the square brackets.** `{ sym: 1 }` creates an ordinary string property `'sym'` rather than a symbol key; the correct form is `{ [sym]: 1 }`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.