Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Тип Symbol у JavaScript». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`Symbol` це примітивний тип, значення якого унікальне та незмінне, і його можна використовувати як ключ властивості об'єкта.** Два символи з однаковим описом ніколи не рівні: `Symbol('id') === Symbol('id')` дає `false`. Символьні ключі не потрапляють у `for...in`, `Object.keys()` і `JSON.stringify()`, тому підходять для «прихованих» внутрішніх даних, які не конфліктують з чужим кодом; дістати їх можна через `Object.getOwnPropertySymbols()`. Глобальний реєстр `Symbol.for(key)` повертає той самий символ у різних частинах програми, а системні символи на кшталт `Symbol.iterator` дозволяють змінювати поведінку об'єктів. ```javascript const id = Symbol('id'); const user = { name: 'Alex', [id]: 123 }; console.log(user[id], Object.keys(user)); // 123 ['name'] ``` **Ключове:** `Symbol` це унікальний ідентифікатор для ключів властивостей, невидимий для звичайного перебору об'єкта.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`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 }`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.