Skip to main content

Тип Symbol у JavaScript

Symbol це унікальне та незмінне значення, яке можна використовувати як ключ властивості об'єкта. Кожен Symbol унікальний, навіть якщо в нього такий самий опис, як у іншого символу.

Теорія

TL;DR

  • Symbol це примітивний тип, поряд зі string, number, boolean та іншими.
  • Кожен виклик Symbol('id') створює нове унікальне значення.
  • Символ можна використати як ключ властивості: { [sym]: value }.
  • Символьні ключі не видно в for...in, Object.keys() і JSON.stringify().
  • Дістати їх можна через Object.getOwnPropertySymbols().
  • Symbol.for() дає глобальний спільний символ, Symbol.keyFor() повертає його ім'я.
  • Системні символи (Symbol.iterator, Symbol.toPrimitive та інші) змінюють поведінку об'єктів.

Швидкий приклад

javascript
const id1 = Symbol('id'); const id2 = Symbol('id'); console.log(id1 === id2); // false

Попри однаковий опис 'id', символи не рівні. Кожен Symbol це унікальний ідентифікатор, а опис потрібен лише для зручності налагодження.

Навіщо потрібен Symbol

До появи символів ключами властивостей об'єкта могли бути тільки рядки. Іноді треба додати в об'єкт «приховану» властивість так, щоб вона не заважала решті коду, наприклад стороннім бібліотекам. Саме тут і допомагає Symbol.

javascript
const id = Symbol('id'); const user = { name: 'Alex', [id]: 123, // символ як ключ }; console.log(user); // { name: 'Alex', [Symbol(id)]: 123 } console.log(user[id]); // 123 console.log(Object.keys(user)); // ['name'], символа не видно

Символьні ключі не беруть участі у for...in та Object.keys() і не конфліктують з іншими властивостями. Це зручно для внутрішніх даних або «приватних» властивостей.

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']

Тобто властивість [TOKEN] існує, але вона «невидима» для більшості операцій. Щоб отримати символьні властивості, є окремий метод:

javascript
const symbols = Object.getOwnPropertySymbols(session); console.log(symbols); // [Symbol(token)] console.log(session[symbols[0]]); // secret-token-123

Порівняння Symbol з іншими типами як ключами:

ТипМоже бути ключем об'єктаУнікальністьБере участь у for...in
stringТакНіТак
numberНі, перетворюється на рядокНіТак, як рядок
SymbolТакТакНі

Symbol не приводиться до рядка неявно

javascript
const sym = Symbol('id'); console.log('Мій символ: ' + sym); // TypeError

Щоб вивести символ як рядок, робіть це явно:

javascript
console.log(sym.toString()); // Symbol(id) console.log(String(sym)); // Symbol(id) console.log(sym.description); // id

Глобальні символи: Symbol.for і Symbol.keyFor

Іноді потрібно, щоб один і той самий Symbol використовувався в різних частинах програми. Для цього є глобальний реєстр символів:

javascript
const a = Symbol.for('shared'); const b = Symbol.for('shared'); console.log(a === b); // true
  • Symbol.for(key) створює новий глобальний символ або повертає вже наявний.
  • Symbol.keyFor(sym) повертає ім'я, під яким символ зареєстровано:
javascript
console.log(Symbol.keyFor(a)); // 'shared'

Для звичайного Symbol('id'), створеного поза реєстром, Symbol.keyFor() поверне undefined.

Системні символи (well-known symbols)

JavaScript визначає кілька вбудованих символів, які дозволяють перевизначати поведінку об'єктів:

СимволДля чого використовується
Symbol.iteratorРобить об'єкт ітерованим (for...of)
Symbol.toPrimitiveКерує перетворенням об'єкта на примітив
Symbol.toStringTagВизначає ім'я для Object.prototype.toString
Symbol.hasInstanceВизначає поведінку оператора instanceof
Symbol.speciesКонтролює створення похідних класів
Symbol.asyncIteratorДля асинхронних ітераторів

Приклад Symbol.iterator:

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 }

Завдяки Symbol.iterator звичайний об'єкт став ітерованим.

Коли застосовувати на практиці

Використовуйте Symbol, коли:

  • потрібен унікальний ідентифікатор, який не перетнеться з іншими властивостями;
  • треба додати «приватну» властивість в об'єкт або клас;
  • треба налаштувати поведінку об'єктів через системні символи (Symbol.iterator, Symbol.toPrimitive та інші).

Коротке резюме:

ЩоОпис
ТипПримітивний (symbol)
Головна особливістьУнікальність
СтворенняSymbol('опис')
Ключі об'єктівМожна використовувати як ключ, унікальний і прихований
Глобальні символиSymbol.for() та Symbol.keyFor()
Системні символиДозволяють перевизначати поведінку JS

Типові помилки

  • Викликати Symbol через new. new Symbol('id') кидає TypeError: це примітив, а не конструктор.
  • Порівнювати символи за описом. Symbol('id') === Symbol('id') завжди false; спільний символ дає лише Symbol.for('id').
  • Неявно склеювати символ з рядком. 'x' + sym кидає TypeError, потрібен явний String(sym) або sym.toString().
  • Вважати символьні властивості справді приватними. Вони лише приховані від звичайного перебору, але Object.getOwnPropertySymbols() і Reflect.ownKeys() їх покажуть.
  • Чекати символьні ключі в JSON. JSON.stringify() їх мовчки викидає, тому дані, потрібні для серіалізації, не варто ховати за символом.
  • Забувати квадратні дужки. { sym: 1 } створить звичайну рядкову властивість 'sym', а не символьний ключ; правильно { [sym]: 1 }.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.