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: "a.ivanov@primer.ru",
    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: "a.ivanov@primer.ru", 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": "a.***@primer.ru", "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, 'RUB'),
  tax:      new Money(15.92, 'RUB'),
  issuedAt: new Date('2026-03-10T14:22:00Z')
}

JSON.stringify(invoice, null, 2)
// {
//   "invoiceId": "inv_8f2a91bc",
//   "subtotal": { "amount": 199, "currency": "RUB", "formatted": "RUB 199.00" },
//   "tax": { "amount": 15.92, "currency": "RUB", "formatted": "RUB 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: "ru-central-1"
}

JSON.stringify(metrics, bigIntReplacer, 2)
// {
//   "requestCount": "9007199254741234",
//   "service": "ingestion-worker",
//   "region": "ru-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:    'ru-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 (например, true вместо true, но отображает функции и Symbol вместо того, чтобы пропускать их), что делает его идеальным для отладочных скриптов 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.