JSON Formatter JavaScript — JSON.stringify()
直接在浏览器中使用免费的 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 参数,一个调用即可实现两种模式。
{"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) 则输出紧凑的单行结果。
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 写入配置文件时常用的组合模式:
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 — 白名单指定键
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 — 转换值
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
// }this 指向包含当前键的对象。 第一次调用传入空字符串作为键,整个被序列化的值作为值——返回它不变即可继续正常序列化。处理不可序列化类型
并非所有 JavaScript 值都能直接映射到 JSON。了解每种类型的行为, 可以避免生产代码中静默的数据丢失和意外的运行时错误。
Date — 通过 toJSON() 自动处理
Date 对象实现了 toJSON() 方法,返回 ISO 8601 格式字符串。 JSON.stringify() 在序列化前会自动调用 toJSON(), 无需自定义处理。
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 更为简洁。
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
// 这会抛出: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
// 这会抛出: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——如需可读输出,请显式传入相应参数。
格式化文件与 API 响应中的 JSON
在 Node.js(18+)中,经常需要重新格式化 JSON 配置文件,或在调试时格式化输出 API 响应。 两种场景使用相同的两步方式:先用 JSON.parse() 解析原始文本,再用 JSON.stringify() 重新序列化。
读取并重写 JSON 配置文件
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)
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()。
// 模式一: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')// 模式二: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 操作的事实标准。
# 用 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)))
"# 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}'"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 路由中使用它。
npm install 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 响应或文件输出。
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 流式解析
npm install 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 无需任何第三方包即可处理。
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() 切换到流式处理。 对于 NDJSON / JSON Lines,使用 readline——无需额外依赖。常见错误
以下四个错误在代码审查和生产 bug 报告中反复出现。每一个都涉及 JSON.stringify() 的某个细微行为——容易忽视,事后难以调试。
问题: 值为 undefined 的对象属性在 JSON 输出中被完全省略——没有任何警告或报错。当对象存在可选字段时,这会导致不可见的数据丢失。
解决方案: 对于必须出现在序列化输出中的有意缺失值,使用 null。只对应当被排除在 JSON 之外的字段保留 undefined。
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
// }问题: 向 JSON.stringify() 传入 BigInt 值会在运行时抛出 TypeError。这是硬崩溃,而非静默忽略——如果任何数值字段超过 Number.MAX_SAFE_INTEGER,将在生产环境中暴露。
解决方案: 使用 replacer 函数在序列化前将 BigInt 值转换为字符串。或者在数据层将 BigInt 转换为字符串或 Number,再传入 JSON.stringify。
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 BigIntfunction 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 库作为原生处理循环结构的直接替代品。
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 JSONimport { 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)问题: 向 JSON.stringify() 传入大于 10 的 space 值不会抛出错误——该值会被静默截断为 10。期望使用 20 个空格缩进深层嵌套的开发者只会得到 10 个,导致生成文件的格式出乎意料。
解决方案: 最大缩进为 10 个空格。对于深层结构,建议使用 2 个空格缩进(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 维护的额外开销并不值得。
常见问题
如何在 JavaScript 中格式化输出 JSON?
调用 JSON.stringify(data, null, 2)——第三个参数控制缩进。传入 2 或 4 表示使用相应数量的空格,传入 "\t" 使用制表符。无需导入或安装:JSON 是每个 JavaScript 环境(包括浏览器和 Node.js)中的全局对象。
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。
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。
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" 的字符串。
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() 重新序列化。两个调用可以在一行内链式完成,方便快速调试。
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、循环引用的限制也一致。
// 适用于 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,无需任何环境配置,即可获得格式化并高亮显示的结果。
相关工具
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.
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.