Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Метод toJSON() у JavaScript». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`toJSON()` це спеціальний метод, який JavaScript викликає автоматично під час серіалізації об'єкта через `JSON.stringify()`**, і він дозволяє контролювати, що саме потрапить у JSON-рядок. Якщо метод є, серіалізується не сам об'єкт, а результат його виклику; працює це рекурсивно для вкладених об'єктів і доступне у власних класах. Повертати можна будь-яке значення: об'єкт, рядок, число або `null`. Саме так вбудований `Date` перетворюється на ISO-рядок. ```javascript const user = { name: 'Alice', password: 'secret', toJSON() { return { name: this.name }; } }; JSON.stringify(user); // '{"name":"Alice"}' ``` **Ключове:** `toJSON()` працює лише на серіалізацію, `JSON.parse()` про нього нічого не знає.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`toJSON()` це спеціальний метод, який JavaScript викликає автоматично під час серіалізації об'єкта через `JSON.stringify()`.** Він дозволяє контролювати, що саме потрапить у JSON-рядок: якщо в об'єкта є `toJSON()`, серіалізується результат виклику цього методу, а не сам об'єкт. ## Теорія ### TL;DR - `JSON.stringify(obj)` спершу перевіряє, чи є в об'єкта метод `toJSON()`. - Якщо є, серіалізується **результат** його виклику, а не сам об'єкт. - Працює рекурсивно: `toJSON()` вкладеного об'єкта теж викликається. - Можна оголошувати у власних класах, зручно для «чистого» вигляду даних. - Повертати дозволено будь-яке значення: об'єкт, рядок, число, `null`. - `Date` має власний `toJSON()`, тому автоматично стає ISO-рядком. - На `JSON.parse()` метод не впливає взагалі. ### Швидкий приклад ```javascript const user = { name: 'Alice', age: 25, password: 'secret', toJSON() { // обираємо, що потрапить у JSON return { name: this.name, age: this.age }; } }; console.log(JSON.stringify(user)); // '{"name":"Alice","age":25}' ``` `password` не потрапив у JSON, бо `toJSON()` повертає лише `name` і `age`. ### Як це працює під капотом Коли ви викликаєте: ```javascript JSON.stringify(obj) ``` JavaScript робить таке: 1. Перевіряє, чи є в `obj` метод `toJSON()`. Якщо є, викликає його: ```javascript const value = obj.toJSON(); ``` 2. Серіалізує **результат** виклику, а не сам об'єкт. Тобто `toJSON()` це точка розширення самого формату: тип сам вирішує, яким він є у JSON. ### Рекурсія у вкладених об'єктах `toJSON()` спрацьовує для всіх вкладених об'єктів, а не тільки для кореневого. ```javascript const user = { name: 'Alice', stats: { score: 42, toJSON() { return 'Top Secret'; // підміняємо об'єкт рядком } } }; console.log(JSON.stringify(user)); // '{"name":"Alice","stats":"Top Secret"}' ``` Метод `toJSON()` усередині `stats` викликався автоматично і підмінив вкладений об'єкт. ### toJSON() у класах і у вбудованих типах Метод зручно оголошувати у власних класах, щоб красиво серіалізувати екземпляри: ```javascript class User { constructor(name, age) { this.name = name; this.age = age; } toJSON() { return { user: this.name, age: this.age }; } } const alice = new User('Alice', 25); console.log(JSON.stringify(alice)); // '{"user":"Alice","age":25}' ``` Так визначають «чисте» представлення даних, наприклад для відправки на сервер. Вбудовані типи поводяться по-різному: | Тип | Що робить `toJSON()` | Приклад | | --- | --- | --- | | `Date` | Повертає ISO-рядок | `new Date().toJSON()` дає `"2025-10-14T17:00:00.000Z"` | | `Map` / `Set` | Не серіалізуються (за замовчуванням) | `JSON.stringify(new Map())` дає `{}` | | `BigInt` | Не підтримується | Помилка: *TypeError: Do not know how to serialize a BigInt* | ### Що можна повертати і як це поєднується з replacer Повертати можна **будь-яке значення**: рядок, число, навіть `null`. ```javascript const product = { name: 'T-shirt', price: 1500, toJSON() { return `${this.name}: ${this.price} UAH`; } }; console.log(JSON.stringify(product)); // '"T-shirt: 1500 UAH"' ``` Повернутий рядок стає результатом серіалізації цілком. Якщо в об'єкта є і `toJSON()`, і переданий `replacer`, то спершу викликається `toJSON()`, а вже його результат потрапляє у `replacer`: ```javascript const obj = { name: 'Alice', toJSON() { return { custom: true }; } }; console.log(JSON.stringify(obj, (key, value) => { if (key === 'custom') return 'ok'; return value; })); // '{"custom":"ok"}' ``` ### Підсумок | Питання | Відповідь | | --- | --- | | Що робить | Визначає, **що саме буде серіалізовано** у `JSON.stringify()` | | Де викликається | Автоматично під час `JSON.stringify()` | | Що повертає | Будь-яке значення (об'єкт, рядок, число тощо) | | Чи працює рекурсивно | Так, для вкладених об'єктів | | Чи можна в класах | Так | | Чи впливає на `JSON.parse()` | Ні, працює лише на серіалізацію | ### Типові помилки - **Чекати, що `JSON.parse()` поверне екземпляр класу.** `toJSON()` односторонній: для зворотного перетворення потрібен власний конструктор, фабрика або `reviver` у `JSON.parse()`. - **Оголошувати `toJSON` як стрілкову функцію у полі класу.** Тоді `this` вказує не туди, куди ви очікуєте; потрібен звичайний метод. - **Повертати з `toJSON()` сам об'єкт (`return this`).** Для кореневого виклику це нескінченна рекурсія або той самий результат без користі. - **Думати, що `toJSON()` шифрує чи захищає дані.** Він лише формує представлення; приховане поле легко дістати напряму з об'єкта. - **Забувати, що метод спрацьовує і для вкладених значень.** Один `toJSON()` глибоко в дереві може непомітно змінити весь payload. - **Розраховувати на `toJSON()` для `Map`, `Set` чи `BigInt`.** У них його немає (а `BigInt` кидає `TypeError`), тому перетворення треба писати самому.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.