Skip to main content

Метод toJSON() у JavaScript

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), тому перетворення треба писати самому.

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

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

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