JSON Formatter JavaScript — JSON.stringify()

·Front-end & Node.js Developer·审阅者Marcus Webb·发布日期

直接在浏览器中使用免费的 JSON格式化工具,无需安装。

在线试用 JSON格式化工具 →

在 Node.js 中调试 API 响应时,一大堆压缩后的 JSON 是最让人头疼的——只需一行 JSON.stringify(data, null, 2), 结构立刻变得清晰可读。在 JavaScript 中 格式化 JSON, 完全不需要任何额外工具: JSON.stringify 内置于每个浏览器和 Node.js 环境,无需安装。 如果只需快速得到结果而无需编写代码,ToolDeck 的 JSON Formatter 可立即完成。本指南涵盖所有实用内容: space 参数、replacer 数组与函数、处理 Date BigInt 和循环引用、Node.js(18+)中读写 JSON 文件、CLI 格式化,以及用于生产序列化的 fast-json-stringify 库。

  • JSON.stringify(data, null, 2) 内置于每个浏览器和 Node.js——无需安装。
  • replacer 参数接受数组(键白名单)或函数(转换值)——可用于屏蔽敏感字段。
  • Date 对象通过 toJSON() 自动序列化为 ISO 8601 字符串;BigInt 会抛出 TypeError,需要自定义 replacer。
  • 循环引用会抛出 TypeError——使用带 seen Set 的 replacer 函数修复,或使用 flatted 库。
  • CLI 格式化可使用 node -p "JSON.stringify(require('./file.json'),null,2)"——无需额外工具。

什么是 JSON 格式化?

JSON 格式化(也称为 pretty-printing)将紧凑压缩的 JSON 字符串转换为具有一致缩进和换行的 人类可读布局。底层数据完全相同——只有空白符发生了变化。紧凑 JSON 适用于每个字节都至关重要的网络传输; 格式化 JSON 则更适合调试、代码审查和日志检查。JavaScript 的 JSON.stringify() 只需切换 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 — 最简示例
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 参数变体
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)

// 制表符缩进(部分 linter 和配置工具偏好)
JSON.stringify(telemetryEvent, null, '\t')

// 紧凑——无空白(用于网络传输)
JSON.stringify(telemetryEvent)
// {"eventId":"evt_3c7f9a2b","service":"checkout-api",...}
注意:undefined、函数和 Symbol 值会被静默忽略。 如果属性值为 undefined,该键将完全不出现在序列化字符串中—— 这在记录含可选字段的对象时是常见的 bug 来源。

Replacer 函数 — 过滤与转换输出

JSON.stringify() 的第二个参数是 replacer,有两种形式:数组——白名单指定要包含的键;函数——对每个键值对调用,可过滤、转换或脱敏值。 需要快速取子集时我用数组形式,需要在记录日志前屏蔽敏感数据时用函数形式。

数组 Replacer — 白名单指定键

JavaScript — 数组 replacer
const order = {
  orderId: "ord_8f2a91bc",
  customer: {
    id: "usr_4421",
    email: "z.wei@example.cn",
    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 — 函数 replacer
const auditRecord = {
  requestId: "req_7d2e91",
  user: { id: "usr_4421", email: "z.wei@example.cn", 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": "z.***@example.cn", "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 序列化
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"'

自定义类 — 实现 toJSON()

任何类都可以实现 toJSON() 方法, JSON.stringify() 在序列化时会自动调用它。对于在整个代码库中频繁出现的领域类型, 这比全局 replacer 更为简洁。

JavaScript — 自定义 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, 'CNY'),
  tax:      new Money(15.92, 'CNY'),
  issuedAt: new Date('2026-03-10T14:22:00Z')
}

JSON.stringify(invoice, null, 2)
// {
//   "invoiceId": "inv_8f2a91bc",
//   "subtotal": { "amount": 199, "currency": "CNY", "formatted": "CNY 199.00" },
//   "tax": { "amount": 15.92, "currency": "CNY", "formatted": "CNY 15.92" },
//   "issuedAt": "2026-03-10T14:22:00.000Z"
// }
注意:toJSON() 的优先级高于 replacer 函数。 两者同时存在时,toJSON() 先执行—— replacer 接收的是已转换后的值,而非原始类实例。

BigInt — 不用 Replacer 会抛出 TypeError

JavaScript — BigInt replacer
// 这会抛出:TypeError: Do not know how to serialize a BigInt
// JSON.stringify({ sessionId: 9007199254741234n })

// 修复:在 replacer 中将 BigInt 转换为字符串
function bigIntReplacer(_key, value) {
  return typeof value === 'bigint' ? value.toString() : value
}

const metrics = {
  requestCount: 9007199254741234n,  // 超过 Number.MAX_SAFE_INTEGER
  service: "ingestion-worker",
  region: "cn-north-1"
}

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

循环引用 — 不用 seen Set 会抛出 TypeError

JavaScript — 循环引用 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——如需可读输出,请显式传入相应参数。

参数
类型
默认值
说明
value
any
要序列化的值。对象、数组、字符串、数字、布尔值和 null 均原生支持。
replacer
function | Array<string | number> | null
null
过滤或转换键值对。数组 = 要包含的键白名单;函数 = 对每个键值对调用。
space
number | string | null
null
缩进。数字 = 每级空格数(最大 10);字符串 = 字面缩进(如 "\t");null 或 0 = 紧凑输出。

格式化文件与 API 响应中的 JSON

在 Node.js(18+)中,经常需要重新格式化 JSON 配置文件,或在调试时格式化输出 API 响应。 两种场景使用相同的两步方式:先用 JSON.parse() 解析原始文本,再用 JSON.stringify() 重新序列化。

读取并重写 JSON 配置文件

Node.js 18+ — 重新格式化 JSON 文件(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 时 JSON.parse 抛出 SyntaxError
  // 文件不存在时 readFileSync 抛出 ENOENT
}

异步文件格式化(fs/promises)

Node.js 18+ — 异步文件格式化
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} 个顶层键`)

格式化 fetch() 响应中的 JSON

在 Node.js 18+ 或浏览器中构建或调试 API 客户端时,格式化输出响应体是了解服务器返回内容的最快方式。 标准模式是将 response.json()(已解析对象) 传入 JSON.stringify()。 如果需要先获取原始字符串——例如计算哈希或原样记录—— 可以先用 response.text(), 再用 JSON.parse()

JavaScript — fetch + 格式化输出(Node.js 18+ 或浏览器)
// 模式一:response.json() → 格式化输出
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()
// 模式二:response.text() → 解析 → 格式化
// 需要同时记录原始响应和格式化输出时使用
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))
  }
}

命令行格式化

Node.js 自带足够的能力,无需任何额外工具即可在终端格式化 JSON。 以下一行命令在 CI 脚本、部署流水线和 shell 别名中非常实用。 如需更快速的交互式使用,可安装 jq—— 命令行 JSON 操作的事实标准。

bash — 用 Node.js 格式化 JSON 文件
# 用 node -p(print)格式化 package.json
node -p "JSON.stringify(require('./package.json'), null, 2)"

# 从标准输入格式化(管道友好,适用于 CI)
echo '{"port":3000,"env":"production"}' | node -e "
  const d = require('fs').readFileSync(0, 'utf8')
  console.log(JSON.stringify(JSON.parse(d), null, 2))
"

# 格式化保存到文件的 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 — 通用替代方案
# Python 备选(macOS 和大多数 Linux 发行版预装)
cat api-response.json | python3 -m json.tool

# jq — 最快且功能最丰富(brew install jq / apt install jq)
cat api-response.json | jq .

# jq — 一步格式化并过滤
cat api-response.json | jq '.data.users[] | {id, email}'
注意:在 ESM 模式(如 package.json 中含 "type": "module")运行 Node.js 时, 一行命令中无法使用 require()。 请改用 --input-type=module fs.readFileSync, 或如上所示切换到带有 CommonJS 代码片段的 node -e

如果完全不在终端环境中——粘贴 Postman 响应或日志文件——ToolDeck 的 JSON Formatter 可让您一步完成粘贴、格式化和复制,并带有语法高亮和内置验证。

高性能替代方案 — fast-json-stringify

fast-json-stringify 根据 JSON Schema 生成专用的序列化函数。由于它提前知道数据结构, 可以跳过类型检查并使用字符串拼接代替递归遍历——基准测试通常显示对大型、重复 payload 比 JSON.stringify() 快 2–5 倍。我在序列化开销出现在性能分析报告中的高频 API 路由中使用它。

bash
npm install fast-json-stringify
JavaScript — 用于遥测事件的 fast-json-stringify
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:    'cn-north-1'
}

const json = serializeTelemetryEvent(event)
// '{"eventId":"evt_3c7f9a2b","service":"checkout-api","severity":"warn",...}'
注意:fast-json-stringify 专为结构化数据的生产序列化设计—— 它始终输出紧凑格式(无格式化)。开发调试时如需人类可读的输出, 请正常使用 JSON.stringify(data, null, 2)

带语法高亮的终端输出

Node.js 内置的 util.inspect() 可输出彩色的、针对终端显示优化的人类可读内容。它原生处理循环引用和 BigInt, 并递归渲染任意深度的嵌套对象。输出不是有效的 JSON——它使用 JavaScript 语法 (例如渲染函数和 Symbol 而非忽略它们),这使其非常适合 Node.js 调试脚本, 但不适合 API 响应或文件输出。

Node.js 18+ — 带颜色的 util.inspect
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.parse() 的下游系统都会报错。 仅将其用于交互式终端调试。

处理大型 JSON 文件

JSON.parse() 在解析之前会将整个文件载入内存——对小 payload 没问题,但对超过 50–100 MB 的文件—— 如数据库导出、应用日志转储或分析批次——则不切实际。 对于这些情况,Node.js Streams 和 stream-json 库可以逐条处理记录而不耗尽堆内存。

使用 stream-json 流式解析

bash
npm install stream-json
Node.js 18+ — stream-json 处理大型数组
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(换行符分隔 JSON)每行存储一个 JSON 对象,常见于 Kafka 导出、BigQuery 输出和结构化日志流水线。 Node.js 内置的 readline 无需任何第三方包即可处理。

Node.js 18+ — 用 readline 处理 NDJSON
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 文件超过 50–100 MB 或需要处理无界流(Kafka、日志流水线)时, 从 JSON.parse() 切换到流式处理。 对于 NDJSON / JSON Lines,使用 readline——无需额外依赖。

常见错误

以下四个错误在代码审查和生产 bug 报告中反复出现。每一个都涉及 JSON.stringify() 的某个细微行为——容易忽视,事后难以调试。

忘记 undefined 值会被静默丢弃

问题: 值为 undefined 的对象属性在 JSON 输出中被完全省略——没有任何警告或报错。当对象存在可选字段时,这会导致不可见的数据丢失。

解决方案: 对于必须出现在序列化输出中的有意缺失值,使用 null。只对应当被排除在 JSON 之外的字段保留 undefined。

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

问题: 向 JSON.stringify() 传入 BigInt 值会在运行时抛出 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 结果集——在传入 JSON.stringify() 时会抛出 TypeError。该错误只在序列化时发生,通常距离循环引用的创建处很远。

解决方案: 使用带 WeakSet 的 replacer 函数检测并替换循环引用,或安装 flatted 库作为原生处理循环结构的直接替代品。

Before · JavaScript
After · JavaScript
const dept = { id: "dept_eng", name: "工程部" }
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: "工程部" }
const team = { id: "team_frontend", dept }
dept.teams = [team]

// flatted 处理循环引用——注意:输出为 flatted 格式,非标准 JSON
stringify(dept)

// 或使用基于 WeakSet 的 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(被静默截断)

问题: 向 JSON.stringify() 传入大于 10 的 space 值不会抛出错误——该值会被静默截断为 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 与替代方案对比

不同场景需要不同工具。带 replacer 的 JSON.stringify 无需任何依赖即可覆盖大多数生产场景。需要彩色输出且不需要有效 JSON 时, util.inspect 是快速终端调试的正确选择。 fast-json-stringify 在性能分析显示序列化开销的高吞吐量路由中值得使用;其他情况下,schema 维护的额外开销并不值得。

方法
格式化输出
有效 JSON
Non-ASCII
自定义类型
循环引用
需要安装
JSON.stringify
⚠️ 通过 replacer
✗ (抛出异常)
JSON.stringify + replacer
✅ 完全控制
util.inspect
✅ 原生支持
否(Node 内置)
fast-json-stringify
❌ 仅 schema
npm install
flatted
✗(自定义格式)
✅ 仅循环引用
npm install
jq (CLI)
N/A
N/A
系统安装

常见问题

如何在 JavaScript 中格式化输出 JSON?

调用 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
// }

JSON.stringify() 中的 space 参数有什么作用?

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" }

格式化 JSON 时如何处理 Date 对象?

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
// }

如何在 JavaScript 中格式化 JSON 字符串(而非对象)?

先用 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 起)的内置全局对象——无需引入任何脚本或 import。打开 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 中的大文件处理。当只需检查或分享格式化的代码片段时, ToolDeck 的 JSON Formatter 是最快的途径:粘贴 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.