Suggest an editImprove this articleRefine the answer for “The toJSON() method in JavaScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`toJSON()` is a special method that JavaScript calls automatically when an object is serialized through `JSON.stringify()`**, and it lets you control exactly what ends up in the JSON string. When the method exists, it is not the object itself that gets serialized but the result of calling it; this works recursively for nested objects and is available in your own classes. It may return any value: an object, a string, a number or `null`. This is exactly how the built-in `Date` turns into an ISO string. ```javascript const user = { name: 'Alice', password: 'secret', toJSON() { return { name: this.name }; } }; JSON.stringify(user); // '{"name":"Alice"}' ``` **Key point:** `toJSON()` only affects serialization, `JSON.parse()` knows nothing about it.Shown above the full answer for quick recall.Answer (EN)Image**`toJSON()` is a special method that JavaScript calls automatically when an object is serialized through `JSON.stringify()`.** It lets you control exactly what ends up in the JSON string: if an object has `toJSON()`, what gets serialized is the result of calling that method, not the object itself. ## Theory ### TL;DR - `JSON.stringify(obj)` first checks whether the object has a `toJSON()` method. - If it does, the **result** of that call is serialized instead of the object. - It works recursively: a nested object's `toJSON()` is called too. - You can declare it in your own classes, handy for a clean data shape. - It may return any value: an object, a string, a number, `null`. - `Date` has its own `toJSON()`, which is why it automatically becomes an ISO string. - It has no effect on `JSON.parse()` at all. ### Quick example ```javascript const user = { name: 'Alice', age: 25, password: 'secret', toJSON() { // pick what ends up in the JSON return { name: this.name, age: this.age }; } }; console.log(JSON.stringify(user)); // '{"name":"Alice","age":25}' ``` `password` did not make it into the JSON, because `toJSON()` returns only `name` and `age`. ### How it works under the hood When you call: ```javascript JSON.stringify(obj) ``` JavaScript does the following: 1. It checks whether `obj` has a `toJSON()` method. If it does, it calls it: ```javascript const value = obj.toJSON(); ``` 2. It serializes the **result** of that call, not the object itself. In other words, `toJSON()` is an extension point of the format itself: a type decides on its own what it looks like in JSON. ### Recursion in nested objects `toJSON()` fires for every nested object, not only for the root one. ```javascript const user = { name: 'Alice', stats: { score: 42, toJSON() { return 'Top Secret'; // replace the object with a string } } }; console.log(JSON.stringify(user)); // '{"name":"Alice","stats":"Top Secret"}' ``` The `toJSON()` method inside `stats` was called automatically and replaced the nested object. ### toJSON() in classes and built-in types The method is convenient in your own classes, so instances serialize nicely: ```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}' ``` This is how you define a clean representation of the data, for example for sending it to a server. Built-in types behave differently: | Type | What `toJSON()` does | Example | | --- | --- | --- | | `Date` | Returns an ISO string | `new Date().toJSON()` gives `"2025-10-14T17:00:00.000Z"` | | `Map` / `Set` | Not serialized (by default) | `JSON.stringify(new Map())` gives `{}` | | `BigInt` | Not supported | Error: *TypeError: Do not know how to serialize a BigInt* | ### What it may return and how it combines with replacer You may return **any value**: a string, a number, even `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"' ``` The returned string becomes the entire serialization result. If an object has both `toJSON()` and a `replacer` passed in, `toJSON()` runs first and its result is what reaches the `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"}' ``` ### Summary | Question | Answer | | --- | --- | | What it does | Defines **what will be serialized** by `JSON.stringify()` | | Where it is called | Automatically during `JSON.stringify()` | | What it returns | Any value (object, string, number and so on) | | Does it work recursively | Yes, for nested objects | | Can it be used in classes | Yes | | Does it affect `JSON.parse()` | No, it only affects serialization | ### Common mistakes - **Expecting `JSON.parse()` to give back a class instance.** `toJSON()` is one way: restoring the type needs your own constructor, a factory, or a `reviver` in `JSON.parse()`. - **Declaring `toJSON` as an arrow function class field.** Then `this` does not point where you expect; use a regular method. - **Returning the object itself (`return this`) from `toJSON()`.** For the root call that is either infinite recursion or the same result with no benefit. - **Thinking `toJSON()` encrypts or protects data.** It only shapes the representation; a hidden field is still readable straight off the object. - **Forgetting that the method also fires for nested values.** A single `toJSON()` deep in the tree can silently change the whole payload. - **Counting on `toJSON()` for `Map`, `Set` or `BigInt`.** They do not have one (and `BigInt` throws a `TypeError`), so you have to write the conversion yourself.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.