JSON Formatter JavaScript — JSON.stringify()

·Front-end & Node.js Developer·ПеревіреноMarcus Webb·Опубліковано

Використовуйте безкоштовний JSON Formatter & Beautifier прямо в браузері — без встановлення.

Спробувати JSON Formatter & Beautifier онлайн →

Коли я налагоджую API-відповіді в Node.js, перше, що сповільнює роботу — це стіна мініфікованого JSON. Один виклик JSON.stringify(data, null, 2) — і структура стає миттєво читаємою. Щоб форматувати JSON у JavaScript, нічого зайвого не потрібно: JSON.stringify вбудований у кожен браузер і Node.js, встановлення не вимагається. Якщо потрібен швидкий результат без написання коду, JSON Formatter від ToolDeck впорається миттєво. Цей посібник охоплює все практичне: параметр space, replacer-масиви та функції, роботу з Date, BigInt та циклічними посиланнями, читання й запис JSON-файлів у Node.js (18+), CLI-форматування та бібліотеку fast-json-stringify для продакшн-серіалізації.

  • JSON.stringify(data, null, 2) вбудований у кожен браузер і Node.js — встановлення не потрібне.
  • Параметр replacer приймає масив (білий список ключів) або функцію (трансформація значень) — використовуй його для маскування чутливих полів.
  • Об'єкти Date серіалізуються автоматично через toJSON() → рядок ISO 8601; BigInt кидає TypeError і потребує спеціального replacer.
  • Циклічні посилання кидають TypeError — виправ за допомогою WeakSet у replacer-функції або бібліотеки flatted.
  • Для CLI-форматування використовуй node -p "JSON.stringify(require('./file.json'),null,2)" — додаткові інструменти не потрібні.

Що таке форматування JSON?

Форматування JSON (також зване pretty-printing) перетворює компактний мініфікований JSON-рядок у зручний для читання формат з однаковими відступами та переносами рядків. Дані залишаються ідентичними — змінюються лише пробільні символи. Компактний JSON оптимальний для передачі мережею, де важливий кожен байт; форматований JSON оптимальний для налагодження, перегляду коду та аналізу логів. Функція JSON.stringify() у JavaScript робить і те, й інше в одному виклику, перемикаючи параметр space.

Before · json
After · json
{"orderId":"ord_8f2a91bc","status":"shipped","items":[{"sku":"HDMI-4K-2M","qty":2,"unitPrice":12.99}],"total":25.98}
{
  "orderId": "ord_8f2a91bc",
  "status": "shipped",
  "items": [
    {
      "sku": "HDMI-4K-2M",
      "qty": 2,
      "unitPrice": 12.99
    }
  ],
  "total": 25.98
}

JSON.stringify() — Вбудований форматтер

JSON.stringify() — глобальна функція у кожному середовищі JavaScript: браузери, Node.js, Deno, Bun — імпорт не потрібен. Третій аргумент, space, керує відступами: передай число для вказаної кількості пробілів на рівень або рядок '\t' для табуляції. Якщо опустити його (або передати null), отримаємо компактний однорядковий вивід.

JavaScript — minimal working example
const serverConfig = {
  host: "api.payments.internal",
  port: 8443,
  workers: 4,
  tls: { enabled: true, cert: "/etc/ssl/certs/api.pem" },
  rateLimit: { requestsPerMinute: 1000, burst: 50 }
}

console.log(JSON.stringify(serverConfig, null, 2))
// {
//   "host": "api.payments.internal",
//   "port": 8443,
//   "workers": 4,
//   "tls": {
//     "enabled": true,
//     "cert": "/etc/ssl/certs/api.pem"
//   },
//   "rateLimit": {
//     "requestsPerMinute": 1000,
//     "burst": 50
//   }
// }

Параметр space приймає число (1–10 пробілів) або рядок. Символ табуляції дає вивід, який надають перевагу багато редакторів і diff-інструментів. Можна комбінувати всі три параметри — ось патерн, який я використовую при записі форматованого JSON у конфіг-файли:

JavaScript — space variations
const telemetryEvent = {
  eventId: "evt_3c7f9a2b",
  service: "checkout-api",
  severity: "warn",
  latencyMs: 342,
  region: "eu-west-1",
  tags: ["payment", "timeout", "retry"]
}

// Відступ 2 пробіли (найпоширеніший у JS-проектах)
JSON.stringify(telemetryEvent, null, 2)

// Відступ табуляцією (надають перевагу деякі лінтери та конфіг-інструменти)
JSON.stringify(telemetryEvent, null, '\t')

// Компактно — без пробілів (для передачі мережею)
JSON.stringify(telemetryEvent)
// {"eventId":"evt_3c7f9a2b","service":"checkout-api",...}
Примітка:Значення undefined, функції та Symbol мовчки виключаються з виводу. Якщо значення властивості — undefined, цей ключ взагалі не з'явиться в серіалізованому рядку — це часте джерело помилок при логуванні об'єктів з опціональними полями.

Replacer-функції — фільтрація та трансформація виводу

Другий аргумент JSON.stringify() — це replacer. Він буває двох форм: масив, що задає білий список конкретних ключів, або функція, що викликається для кожної пари ключ/значення і може фільтрувати, трансформувати або приховувати значення. Масив використовую, коли треба швидко вибрати підмножину; функцію — коли треба замаскувати чутливі дані перед логуванням.

Масив-replacer — білий список ключів

JavaScript — array replacer
const order = {
  orderId: "ord_8f2a91bc",
  customer: {
    id: "usr_4421",
    email: "o.kovalenko@poshta.ua",
    passwordHash: "bcrypt:$2b$12$XKzV..."
  },
  items: [{ sku: "HDMI-4K-2M", qty: 2, unitPrice: 12.99 }],
  createdAt: "2026-03-10T14:22:00Z"
}

// Включити до логу тільки безпечні поля
const safeLog = JSON.stringify(order, ["orderId", "items", "createdAt"], 2)
// {
//   "orderId": "ord_8f2a91bc",
//   "items": [{ "sku": "HDMI-4K-2M", "qty": 2, "unitPrice": 12.99 }],
//   "createdAt": "2026-03-10T14:22:00Z"
// }
// passwordHash та customer.email виключені

Функція-replacer — трансформація значень

JavaScript — function replacer
const auditRecord = {
  requestId: "req_7d2e91",
  user: { id: "usr_4421", email: "o.kovalenko@poshta.ua", apiKey: "sk-live-eKx9..." },
  action: "update_billing",
  timestamp: new Date("2026-03-10T14:22:00Z"),
  durationMs: 87
}

function safeReplacer(key, value) {
  // Приховуємо поля, що схожі на секрети або персональні дані
  if (key === "apiKey") return "[REDACTED]"
  if (key === "email") return value.replace(/(?<=.{2}).+(?=@)/, "***")
  return value
}

console.log(JSON.stringify(auditRecord, safeReplacer, 2))
// {
//   "requestId": "req_7d2e91",
//   "user": { "id": "usr_4421", "email": "o.***@poshta.ua", "apiKey": "[REDACTED]" },
//   "action": "update_billing",
//   "timestamp": "2026-03-10T14:22:00.000Z",
//   "durationMs": 87
// }
Примітка:Replacer-функція викликається з this, що вказує на об'єкт, який містить поточний ключ. Перший виклик передає порожній рядок як ключ і все серіалізоване значення — поверни його без змін, щоб продовжити звичайну серіалізацію.

Робота з несеріалізованими типами

Не всі значення JavaScript акуратно перетворюються на JSON. Знання поведінки кожного типу запобігає мовчазній втраті даних і неочікуваним помилкам у продакшн-коді.

Date — автоматично через toJSON()

Об'єкти Date реалізують метод toJSON(), що повертає рядок ISO 8601. JSON.stringify() викликає toJSON() автоматично перед серіалізацією, тому ніякої спеціальної обробки не потрібно.

JavaScript — Date serialization
const webhook = {
  eventType: "payment.succeeded",
  occurredAt: new Date("2026-03-10T14:22:00Z"),
  processedAt: new Date()
}

JSON.stringify(webhook, null, 2)
// {
//   "eventType": "payment.succeeded",
//   "occurredAt": "2026-03-10T14:22:00.000Z",
//   "processedAt": "2026-03-10T14:22:01.347Z"
// }

// Будь-який об'єкт із методом toJSON() обробляється так само:
const custom = { toJSON: () => "custom-value", hidden: 42 }
JSON.stringify(custom) // '"custom-value"'

Custom Classes — реалізувати toJSON()

Будь-який клас може реалізувати метод toJSON(), і JSON.stringify() викличе його автоматично під час серіалізації. Це чистіше, ніж глобальний replacer для доменних типів, що зустрічаються по всьому коду.

JavaScript — custom toJSON()
class Money {
  constructor(amount, currency) {
    this.amount = amount
    this.currency = currency
  }
  toJSON() {
    // Викликається автоматично JSON.stringify
    return { amount: this.amount, currency: this.currency, formatted: `${this.currency} ${this.amount.toFixed(2)}` }
  }
}

class OrderId {
  constructor(id) { this.id = id }
  toJSON() { return this.id }  // Серіалізувати як простий рядок
}

const invoice = {
  invoiceId: new OrderId('inv_8f2a91bc'),
  subtotal: new Money(199.00, 'UAH'),
  tax:      new Money(15.92, 'UAH'),
  issuedAt: new Date('2026-03-10T14:22:00Z')
}

JSON.stringify(invoice, null, 2)
// {
//   "invoiceId": "inv_8f2a91bc",
//   "subtotal": { "amount": 199, "currency": "UAH", "formatted": "UAH 199.00" },
//   "tax": { "amount": 15.92, "currency": "UAH", "formatted": "UAH 15.92" },
//   "issuedAt": "2026-03-10T14:22:00.000Z"
// }
Примітка:toJSON() має пріоритет над replacer-функцією. Якщо обидва присутні, toJSON() виконується першим — replacer отримує вже перетворене значення, а не вихідний екземпляр класу.

BigInt — TypeError без replacer

JavaScript — BigInt replacer
// Це кидає: TypeError: Do not know how to serialize a BigInt
// JSON.stringify({ sessionId: 9007199254741234n })

// Рішення: конвертувати BigInt у рядок у replacer
function bigIntReplacer(_key, value) {
  return typeof value === 'bigint' ? value.toString() : value
}

const metrics = {
  requestCount: 9007199254741234n,  // перевищує Number.MAX_SAFE_INTEGER
  service: "ingestion-worker",
  region: "ua-central-1"
}

JSON.stringify(metrics, bigIntReplacer, 2)
// {
//   "requestCount": "9007199254741234",
//   "service": "ingestion-worker",
//   "region": "ua-central-1"
// }

Циклічні посилання — TypeError без Seen Set

JavaScript — circular reference replacer
// Це кидає: TypeError: Converting circular structure to JSON
// const node = { id: "n1" }; node.self = node; JSON.stringify(node)

// Рішення: відстежувати побачені об'єкти за допомогою WeakSet
function circularReplacer() {
  const seen = new WeakSet()
  return function (_key, value) {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) return '[Circular]'
      seen.add(value)
    }
    return value
  }
}

const parent = { id: "node_parent", label: "root" }
const child  = { id: "node_child", parent }
parent.child = child  // циклічне посилання

JSON.stringify(parent, circularReplacer(), 2)
// {
//   "id": "node_parent",
//   "label": "root",
//   "child": { "id": "node_child", "parent": "[Circular]" }
// }

// Альтернатива: npm install flatted
// import { stringify } from 'flatted'
// stringify(parent)  // обробляє циклічні посилання нативно

Довідник параметрів JSON.stringify()

Усі три параметри добре підтримуються в кожному сучасному середовищі виконання JavaScript. Значення за замовчуванням дають компактний однорядковий JSON — передавай параметри явно для читаємого виводу.

Параметр
Type
Default
Опис
value
any
Значення для серіалізації. Об'єкти, масиви, рядки, числа, булеві значення та null підтримуються нативно.
replacer
function | Array<string | number> | null
null
Фільтрація або трансформація пар ключ/значення. Масив = білий список ключів для включення. Функція = викликається для кожної пари ключ/значення.
space
number | string | null
null
Відступ. Число = пробіли на рівень (макс. 10). Рядок = символ відступу (наприклад "\t"). null або 0 = компактний вивід.

Форматування JSON з файлу та API-відповіді

У Node.js (18+) часто треба переформатувати JSON-конфіг або красиво вивести API-відповідь для налагодження. Обидва патерни використовують однаковий двокроковий підхід: розібрати сирий текст за допомогою JSON.parse(), потім знову серіалізувати з JSON.stringify().

Читання та перезапис JSON-конфігу

Node.js 18+ — reformat a JSON file (ESM)
import { readFileSync, writeFileSync } from 'fs'

try {
  const raw = readFileSync('./config/database.json', 'utf8')
  const config = JSON.parse(raw)
  writeFileSync('./config/database.json', JSON.stringify(config, null, 2))
  console.log('Конфігурацію успішно переформатовано')
} catch (err) {
  console.error('Помилка при переформатуванні конфігу:', err.message)
  // JSON.parse кидає SyntaxError, якщо файл містить невалідний JSON
  // readFileSync кидає ENOENT, якщо файл не існує
}

Асинхронне переформатування файлу (fs/promises)

Node.js 18+ — async file reformat
import { readFile, writeFile } from 'fs/promises'

async function reformatJson(filePath) {
  const raw = await readFile(filePath, 'utf8')
  const parsed = JSON.parse(raw)
  const formatted = JSON.stringify(parsed, null, 2)
  await writeFile(filePath, formatted, 'utf8')
  return { keys: Object.keys(parsed).length }
}

// Використання
const { keys } = await reformatJson('./config/feature-flags.json')
console.log(`Переформатовано ${keys} ключів верхнього рівня`)

Pretty Print JSON з fetch()-відповіді

При розробці або налагодженні API-клієнта в Node.js 18+ або браузері красивий вивід тіла відповіді — найшвидший спосіб зрозуміти, що повернув сервер. Стандартний патерн: response.json() (розібраний об'єкт) у JSON.stringify(). Якщо спочатку потрібен сирий рядок — наприклад, щоб обчислити хеш або залогувати дослівно — використовуй response.text() потім JSON.parse().

JavaScript — fetch + pretty print (Node.js 18+ or browser)
// Патерн 1: response.json() → pretty print
async function debugEndpoint(url) {
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
  })
  if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`)

  const data = await res.json()
  console.log(JSON.stringify(data, null, 2))
}

await debugEndpoint('https://api.stripe.com/v1/charges?limit=3')
JavaScript — response.text() when you need the raw string first
// Патерн 2: response.text() → parse → format
// Корисно, коли треба залогувати і сиру відповідь, і форматовану
async function inspectRawResponse(url) {
  const res = await fetch(url)
  const raw = await res.text()

  console.log('Довжина сирої відповіді:', raw.length)
  try {
    const parsed = JSON.parse(raw)
    console.log('Форматований:')
    console.log(JSON.stringify(parsed, null, 2))
  } catch {
    console.error('Відповідь не є валідним JSON:', raw.slice(0, 200))
  }
}

Pretty Printing з командного рядка

Node.js достатньо функціональний, щоб форматувати JSON з термінала без додаткових інструментів. Ці однорядники корисні в CI-скриптах, деплой-пайплайнах і псевдонімах shell. Для ще швидшої інтерактивної роботи встанови jq — стандарт де-факто для роботи з JSON у командному рядку.

bash — pretty print a JSON file with Node.js
# Pretty-print package.json за допомогою node -p (print)
node -p "JSON.stringify(require('./package.json'), null, 2)"

# Pretty-print зі stdin (pipe-сумісно, працює в CI)
echo '{"port":3000,"env":"production"}' | node -e "
  const d = require('fs').readFileSync(0, 'utf8')
  console.log(JSON.stringify(JSON.parse(d), null, 2))
"

# Pretty-print збереженої API-відповіді
cat api-response.json | node -e "
  process.stdin.setEncoding('utf8')
  let s = ''
  process.stdin.on('data', c => s += c)
  process.stdin.on('end', () => console.log(JSON.stringify(JSON.parse(s), null, 2)))
"
bash — universal alternatives
# Python fallback (передвстановлений на macOS і більшості Linux-дистрибутивів)
cat api-response.json | python3 -m json.tool

# jq — найшвидший і найфункціональніший (brew install jq / apt install jq)
cat api-response.json | jq .

# jq — pretty-print і фільтрація в одному кроці
cat api-response.json | jq '.data.users[] | {id, email}'
Примітка:При запуску Node.js в ESM-режимі (наприклад, з "type": "module" у package.json) require() недоступний в однорядниках. Використовуй --input-type=module і fs.readFileSync замість нього, або перейди до node -e з CommonJS-сніпетом, як показано вище.

Якщо ти взагалі не в терміналі — вставляєш відповідь із Postman або лог-файл — JSON Formatter від ToolDeck дозволяє вставити, відформатувати й скопіювати за один крок із підсвічуванням синтаксису та вбудованою валідацією.

Високопродуктивна альтернатива — fast-json-stringify

fast-json-stringify генерує спеціалізовану функцію серіалізації з JSON Schema. Оскільки вона знає форму даних заздалегідь, вона може пропустити перевірку типів і використовувати конкатенацію рядків замість рекурсивного обходу — бенчмарки показують типове прискорення в 2–5× порівняно з JSON.stringify() на великих однотипних навантаженнях. Я використовую її на високонавантажених API-роутах, де вартість серіалізації видна в трейсах профайлера.

bash
npm install fast-json-stringify
JavaScript — fast-json-stringify for telemetry events
import fastJson from 'fast-json-stringify'

const serializeTelemetryEvent = fastJson({
  title: 'TelemetryEvent',
  type: 'object',
  properties: {
    eventId:   { type: 'string' },
    service:   { type: 'string' },
    severity:  { type: 'string', enum: ['info', 'warn', 'error'] },
    latencyMs: { type: 'integer' },
    timestamp: { type: 'string' },
    region:    { type: 'string' }
  },
  required: ['eventId', 'service', 'severity', 'latencyMs', 'timestamp']
})

const event = {
  eventId:   'evt_3c7f9a2b',
  service:   'checkout-api',
  severity:  'warn',
  latencyMs: 342,
  timestamp: new Date().toISOString(),
  region:    'ua-central-1'
}

const json = serializeTelemetryEvent(event)
// '{"eventId":"evt_3c7f9a2b","service":"checkout-api","severity":"warn",...}'
Примітка:fast-json-stringify призначений для продакшн-серіалізації структурованих даних — він завжди дає компактний вивід (без pretty-printing). Для читаємого виводу під час розробки використовуй JSON.stringify(data, null, 2) як зазвичай.

Вивід у термінал із підсвічуванням синтаксису

Вбудований у Node.js util.inspect() дає кольоровий, зручний для читання вивід, оптимізований для відображення в терміналі. Він нативно обробляє циклічні посилання та BigInt і рекурсивно відображає вкладені об'єкти до будь-якої глибини. Вивід не є валідним JSON — він використовує синтаксис JavaScript, що робить його ідеальним для налагоджувальних скриптів Node.js, але непридатним для API-відповідей або файлового виводу.

Node.js 18+ — util.inspect with colors
import { inspect } from 'util'

const payload = {
  requestId: "req_7d2e91",
  user: { id: "usr_4421", roles: ["admin", "billing"] },
  metadata: { ipAddress: "203.0.113.42", userAgent: "Mozilla/5.0" },
  createdAt: new Date()
}

// depth: null → розгорнути всі вкладені рівні; colors: true → ANSI-кольори терміналу
console.log(inspect(payload, { colors: true, depth: null }))
Увага:Не використовуй util.inspect() для JSON, що записується у файли, надсилається мережею або зберігається в базі даних. Його вивід — не валідний JSON і викличе помилки парсингу в будь-якій downstream-системі, що викликає JSON.parse() на ньому. Залиш його лише для інтерактивного налагодження в терміналі.

Робота з великими JSON-файлами

JSON.parse() завантажує весь файл у пам'ять перед парсингом — нормально для невеликих даних, але непрактично для файлів понад 50–100 МБ: експортів баз даних, дампів логів або аналітичних батчів. Для таких випадків Node.js Streams і бібліотека stream-json дозволяють обробляти записи по одному, не перевантажуючи купу.

Потоковий парсинг із stream-json

bash
npm install stream-json
Node.js 18+ — stream-json for large arrays
import { pipeline } from 'stream/promises'
import { createReadStream } from 'fs'
import { parser } from 'stream-json'
import { streamArray } from 'stream-json/streamers/StreamArray.js'

// events.json = масив із мільйонів об'єктів — ніколи не завантажується в пам'ять повністю
await pipeline(
  createReadStream('./events.json'),
  parser(),
  streamArray(),
  async function* (source) {
    for await (const { value: event } of source) {
      if (event.severity === 'error') {
        console.log(JSON.stringify(event, null, 2))
      }
    }
  }
)

NDJSON / JSON Lines — без додаткових залежностей

NDJSON (Newline Delimited JSON) зберігає один JSON-об'єкт на рядок і поширений у експортах Kafka, вивантаженнях BigQuery і конвеєрах структурованих логів. Вбудований у Node.js readline обробляє його без сторонніх пакетів.

Node.js 18+ — NDJSON with readline
import { createReadStream } from 'fs'
import { createInterface } from 'readline'

// Формат: один JSON-об'єкт на рядок (логи, експорти Kafka, BigQuery)
const rl = createInterface({
  input: createReadStream('./logs.ndjson'),
  crlfDelay: Infinity
})

for await (const line of rl) {
  if (!line.trim()) continue
  const entry = JSON.parse(line)
  if (entry.level === 'error') {
    console.log(JSON.stringify(entry, null, 2))
  }
}
Примітка:Переходь від JSON.parse() до потокової обробки, коли JSON-файл перевищує 50–100 МБ або при обробці необмеженого потоку (Kafka, лог-пайплайн). Для NDJSON / JSON Lines використовуй readline — додаткові залежності не потрібні.

Поширені помилки

Ці чотири помилки зустрічаються знову і знову в код-рев'ю та звітах про продакшн-баги. Кожна пов'язана з тонкою поведінкою JSON.stringify(), яку легко пропустити і важко налагодити потім.

Забувають, що undefined-значення мовчки видаляються

Проблема: Властивості об'єкта зі значенням undefined повністю виключаються з JSON-виводу — без попереджень і помилок. Це викликає непомітну втрату даних, коли в об'єкті є опціональні поля.

Рішення: Використовуй null для навмисно відсутніх значень, які мають з'явитися в серіалізованому виводі. Залиш undefined тільки для полів, що мають бути виключені з JSON.

Before · JavaScript
After · JavaScript
const userProfile = {
  userId: "usr_4421",
  displayName: "Олексій Коваленко",
  avatarUrl: undefined,   // зникне мовчки
  bio: undefined          // зникне мовчки
}

JSON.stringify(userProfile, null, 2)
// { "userId": "usr_4421", "displayName": "Олексій Коваленко" }
// avatarUrl та bio зникли — без попередження
const userProfile = {
  userId: "usr_4421",
  displayName: "Олексій Коваленко",
  avatarUrl: null,   // явно відсутнє — з'явиться у виводі
  bio: null          // явно відсутнє — з'явиться у виводі
}

JSON.stringify(userProfile, null, 2)
// {
//   "userId": "usr_4421",
//   "displayName": "Олексій Коваленко",
//   "avatarUrl": null,
//   "bio": null
// }
BigInt кидає TypeError

Проблема: Передача BigInt-значення в JSON.stringify() кидає TypeError під час виконання. Це жорстка аварія, а не мовчазне виключення — вона проявиться в продакшні, якщо якесь числове поле перевищить Number.MAX_SAFE_INTEGER.

Рішення: Використовуй replacer-функцію, що конвертує BigInt у рядки перед серіалізацією. Альтернативно: конвертуй BigInt у рядок або Number на рівні даних перед передачею в JSON.stringify.

Before · JavaScript
After · JavaScript
const session = {
  sessionId: 9007199254741234n,  // BigInt-літерал
  userId: "usr_4421",
  startedAt: "2026-03-10T14:00:00Z"
}

JSON.stringify(session, null, 2)
// Uncaught TypeError: Do not know how to serialize a BigInt
function bigIntReplacer(_key, value) {
  return typeof value === 'bigint' ? value.toString() : value
}

const session = {
  sessionId: 9007199254741234n,
  userId: "usr_4421",
  startedAt: "2026-03-10T14:00:00Z"
}

JSON.stringify(session, bigIntReplacer, 2)
// {
//   "sessionId": "9007199254741234",
//   "userId": "usr_4421",
//   "startedAt": "2026-03-10T14:00:00Z"
// }
Аварія через циклічні посилання

Проблема: Об'єкти, що посилаються на самих себе — типові в DOM-деревах, зв'язних списках і деяких ORM-результатах — кидають TypeError при передачі в JSON.stringify(). Помилка виникає лише в момент серіалізації, нерідко далеко від місця створення циклічного посилання.

Рішення: Використовуй replacer-функцію з WeakSet для виявлення та заміни циклічних посилань, або встанови бібліотеку flatted — готову заміну, що нативно обробляє циклічні структури.

Before · JavaScript
After · JavaScript
const dept = { id: "dept_eng", name: "Engineering" }
const team = { id: "team_frontend", dept }
dept.teams = [team]  // циклічне: dept → team → dept

JSON.stringify(dept, null, 2)
// Uncaught TypeError: Converting circular structure to JSON
import { stringify } from 'flatted'  // npm install flatted

const dept = { id: "dept_eng", name: "Engineering" }
const team = { id: "team_frontend", dept }
dept.teams = [team]

// flatted обробляє циклічні посилання — вивід у форматі flatted, не стандартний JSON
stringify(dept)

// Або WeakSet-based replacer для стандартного JSON-виводу:
function circularReplacer() {
  const seen = new WeakSet()
  return (_key, value) => {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) return '[Circular]'
      seen.add(value)
    }
    return value
  }
}
JSON.stringify(dept, circularReplacer(), 2)
Використання space > 10 (мовчки обрізається)

Проблема: Передача значення space більше 10 у JSON.stringify() не кидає помилки — значення мовчки обмежується до 10. Розробники, що очікують 20 пробілів на рівень для глибоких структур, отримають тільки 10, що призведе до несподіваного форматування в згенерованих файлах.

Рішення: Максимальний відступ — 10 пробілів. Для глибоких структур надавай перевагу 2-пробільному відступу (найпоширеніша конвенція в JavaScript-проектах) і покладайся на згортувані редактори для навігації.

Before · JavaScript
After · JavaScript
const deepConfig = { server: { tls: { certs: { primary: "/etc/ssl/api.pem" } } } }

// Очікується відступ 20 пробілів — але space обмежений до 10
JSON.stringify(deepConfig, null, 20)
// Той самий вивід, що і JSON.stringify(deepConfig, null, 10)
// Нема помилки, нема попередження — мовчки обрізано
const deepConfig = { server: { tls: { certs: { primary: "/etc/ssl/api.pem" } } } }

// Використовуй 2 (більшість проектів) або 4 пробіли — ніколи не перевищуй 10
JSON.stringify(deepConfig, null, 2)
// {
//   "server": {
//     "tls": {
//       "certs": {
//         "primary": "/etc/ssl/api.pem"
//       }
//     }
//   }
// }

JSON.stringify vs. Альтернативи — Швидке порівняння

Різні ситуації вимагають різних інструментів. JSON.stringify з replacer покриває більшість продакшн-сценаріїв без залежностей. util.inspect — правильний вибір для швидкого налагодження в терміналі, коли потрібен кольоровий вивід і не потрібен валідний JSON. fast-json-stringify окупається на високонавантажених роутах, де профілювання показує вартість серіалізації; для всього іншого накладні витрати на підтримку схеми того не варті.

Метод
Pretty Output
Valid JSON
Non-ASCII
Custom Types
Circular Refs
Встановлення
JSON.stringify
⚠️ via replacer
✗ (throws)
Ні
JSON.stringify + replacer
✅ повний контроль
Ні
util.inspect
✅ нативно
Ні (Node built-in)
fast-json-stringify
❌ schema-only
npm install
flatted
✗ (custom format)
✅ тільки circular
npm install
jq (CLI)
N/A
N/A
System install

Часті запитання

Як красиво вивести JSON у JavaScript?

Виклич JSON.stringify(data, null, 2) — третій аргумент керує відступами. Передай 2 або 4 для пробілів або "\t" для табуляції. Імпорт чи встановлення не потрібні: JSON — глобальний об'єкт у кожному середовищі JavaScript, включно з браузерами та Node.js.

JavaScript
const config = { host: "api.payments.internal", port: 8443, tls: true }
console.log(JSON.stringify(config, null, 2))
// {
//   "host": "api.payments.internal",
//   "port": 8443,
//   "tls": true
// }

Що робить параметр `space` у JSON.stringify()?

Параметр space керує відступами у виводі. Передай число (1–10) для вказаної кількості пробілів на рівень або рядок на кшталт "\t" для символу табуляції. Значення вище 10 мовчки обмежуються до 10. Передача null, 0 або відсутність параметра дає компактний однорядковий JSON.

JavaScript
const data = { service: "payments", version: 3, active: true }

JSON.stringify(data, null, 2)   // відступ 2 пробіли
JSON.stringify(data, null, 4)   // відступ 4 пробіли
JSON.stringify(data, null, '\t') // відступ табуляцією
JSON.stringify(data)            // компактно: {"service":"payments","version":3,"active":true}

Чому JSON.stringify() повертає undefined для деяких значень?

JSON.stringify мовчки пропускає властивості об'єкта, значення яких — undefined, функції або Symbol — ці типи не мають JSON-представлення. Якщо саме верхньорівневе значення — undefined, функція повертає undefined (не рядок "undefined"). Використовуй null замість undefined для опціональних полів, які мають з'являтися у виводі.

JavaScript
const event = {
  traceId: "tr_9a2f",
  handler: () => {},        // функція — пропускається
  requestId: undefined,     // undefined — пропускається
  sessionId: Symbol("s"),   // Symbol — пропускається
  status: "ok"
}
JSON.stringify(event, null, 2)
// { "traceId": "tr_9a2f", "status": "ok" }

Як обробляти об'єкти Date при форматуванні JSON?

Об'єкти Date мають вбудований метод toJSON(), що повертає рядок ISO 8601, тому JSON.stringify обробляє їх автоматично. Спеціальний replacer для дат не потрібен — серіалізоване значення буде рядком на кшталт "2026-03-10T14:22:00.000Z".

JavaScript
const order = {
  orderId: "ord_8f2a91bc",
  placedAt: new Date("2026-03-10T14:22:00Z"),
  total: 42.98
}
JSON.stringify(order, null, 2)
// {
//   "orderId": "ord_8f2a91bc",
//   "placedAt": "2026-03-10T14:22:00.000Z",
//   "total": 42.98
// }

Як форматувати JSON-рядок (не об'єкт) у JavaScript?

Спочатку розбери рядок за допомогою JSON.parse(), потім знову серіалізуй з JSON.stringify(). Обидва виклики можна поєднати в один рядок для швидкого налагодження.

JavaScript
const raw = '{"endpoint":"/api/v2/users","timeout":30,"retry":true}'
const formatted = JSON.stringify(JSON.parse(raw), null, 2)
console.log(formatted)
// {
//   "endpoint": "/api/v2/users",
//   "timeout": 30,
//   "retry": true
// }

Чи можна використовувати JSON.stringify() у браузері?

Так. JSON — вбудований глобальний об'єкт у кожному сучасному браузері починаючи з IE8 — жодних тегів script чи імпортів не потрібно. Відкрий консоль DevTools і викликай JSON.stringify() напряму. Він працює ідентично версії Node.js, з тим самим підписом параметрів і тими самими обмеженнями щодо BigInt і циклічних посилань.

JavaScript
// Працює у Chrome, Firefox, Safari, Edge — імпорти не потрібні
const payload = { userId: "usr_7b3c", action: "checkout", cart: ["SKU-001", "SKU-002"] }
copy(JSON.stringify(payload, null, 2)) // copy() — допоміжна функція DevTools

JavaScript надає повний контроль — replacer-функції, власний toJSON(), обробка великих файлів у Node.js. Коли потрібно лише перевірити або поділитися відформатованим фрагментом, JSON Formatter від ToolDeck — найшвидший шлях: встав JSON і отримай відформатований результат із підсвічуванням без жодного налаштування оточення.

Пов'язані інструменти

Також доступно на:PythonGoBash
AC
Alex ChenFront-end & Node.js Developer

Alex is a front-end and Node.js developer with extensive experience building web applications and developer tooling. He is passionate about web standards, browser APIs, and the JavaScript ecosystem. In his spare time he contributes to open-source projects and writes about modern JavaScript patterns, performance optimisation, and everything related to the web platform.

MW
Marcus WebbТехнічний рецензент

Marcus specialises in JavaScript performance, build tooling, and the inner workings of the V8 engine. He has spent years profiling and optimising React applications, working on bundler configurations, and squeezing every millisecond out of critical rendering paths. He writes about Core Web Vitals, JavaScript memory management, and the tools developers reach for when performance really matters.