JSON Formatter JavaScript — JSON.stringify()

·Front-end & Node.js Developer·Đánh giá bởiMarcus Webb·Đã xuất bản

Sử dụng Định dạng và Làm đẹp JSON miễn phí trực tiếp trên trình duyệt — không cần cài đặt.

Dùng thử Định dạng và Làm đẹp JSON trực tuyến →

Khi debug các phản hồi API trong Node.js, thứ đầu tiên làm tôi chậm lại là một bức tường JSON được nén — một lần gọi JSON.stringify(data, null, 2) là cấu trúc trở nên dễ đọc ngay lập tức. Để định dạng JSON trong JavaScript, bạn không cần gì ngoài runtime: JSON.stringify đã được tích hợp trong mọi trình duyệt và môi trường Node.js, không cần cài đặt. Nếu bạn chỉ cần kết quả nhanh mà không viết code, Trình định dạng JSON của ToolDeck thực hiện điều đó ngay lập tức. Hướng dẫn này bao gồm mọi thứ thực tế: tham số space, mảng và hàm replacer, xử lý Date, BigInt và tham chiếu vòng, đọc và ghi file JSON trong Node.js (18+), in đẹp từ CLI, và thư viện fast-json-stringify cho serialization trong môi trường production.

  • JSON.stringify(data, null, 2) đã tích hợp trong mọi trình duyệt và Node.js — không cần cài đặt.
  • Tham số replacer nhận một mảng (danh sách trắng key) hoặc hàm (biến đổi giá trị) — dùng để che giấu các trường nhạy cảm.
  • Đối tượng Date serialize tự động qua toJSON() → chuỗi ISO 8601; BigInt ném TypeError và cần replacer tùy chỉnh.
  • Tham chiếu vòng ném TypeError — sửa bằng seen Set trong hàm replacer, hoặc dùng thư viện flatted.
  • Để in đẹp từ CLI dùng node -p "JSON.stringify(require('./file.json'),null,2)" — không cần công cụ thêm.

Định Dạng JSON là Gì?

Định dạng JSON (còn gọi là in đẹp - pretty-printing) chuyển đổi một chuỗi JSON nén thành bố cục dễ đọc cho con người với thụt lề nhất quán và ngắt dòng. Dữ liệu bên trong giống hệt nhau — chỉ khoảng trắng thay đổi. JSON nén tối ưu cho truyền mạng khi mỗi byte quan trọng; JSON định dạng tối ưu cho debug, review code và kiểm tra log. Hàm JSON.stringify() của JavaScript xử lý cả hai trong một lần gọi bằng cách bật tắt tham số 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() — Định Dạng JSON Tích Hợp Sẵn

JSON.stringify() là hàm toàn cục trong mọi môi trường JavaScript — trình duyệt, Node.js, Deno, Bun — không cần import. Đối số thứ ba của nó, space, kiểm soát thụt lề: truyền một số cho số khoảng trắng đó mỗi cấp, hoặc chuỗi '\t' cho tab. Bỏ qua (hoặc truyền null) và bạn sẽ nhận được output gọn một dòng.

JavaScript — ví dụ tối thiểu hoạt động được
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
//   }
// }

Tham số space nhận một số (1–10 khoảng trắng) hoặc chuỗi. Truyền ký tự tab tạo ra output mà nhiều editor và công cụ diff ưa thích. Bạn cũng có thể kết hợp cả ba tham số — đây là mẫu thực tế tôi dùng khi ghi JSON định dạng vào file config:

JavaScript — các biến thể của space
const telemetryEvent = {
  eventId: "evt_3c7f9a2b",
  service: "checkout-api",
  severity: "warn",
  latencyMs: 342,
  region: "eu-west-1",
  tags: ["payment", "timeout", "retry"]
}

// Thụt lề 2 khoảng trắng (phổ biến nhất trong dự án JS)
JSON.stringify(telemetryEvent, null, 2)

// Thụt lề tab (ưa thích bởi một số linter và công cụ config)
JSON.stringify(telemetryEvent, null, '\t')

// Gọn — không có khoảng trắng (để truyền mạng)
JSON.stringify(telemetryEvent)
// {"eventId":"evt_3c7f9a2b","service":"checkout-api",...}
Lưu ý:Các giá trị undefined, function và Symbol bị bỏ qua im lặng khỏi output. Nếu giá trị thuộc tính là undefined, key đó sẽ không xuất hiện trong chuỗi đã serialize — đây là nguồn lỗi phổ biến khi log các đối tượng có trường tùy chọn.

Hàm Replacer — Lọc và Biến Đổi Output

Đối số thứ hai của JSON.stringify() là replacer. Nó có hai dạng: một mảng đặt danh sách trắng các key cụ thể, hoặc một hàm được gọi cho mỗi cặp key/value và có thể lọc, biến đổi hoặc che giấu giá trị. Tôi dùng dạng mảng khi cần một tập con nhanh, và dạng hàm khi cần che giấu dữ liệu nhạy cảm trước khi log.

Array Replacer — Đặt Danh Sách Trắng cho Key Cụ Thể

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

// Chỉ đưa các trường an toàn vào output log
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 và customer.email bị loại trừ

Function Replacer — Biến Đổi Giá Trị

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

function safeReplacer(key, value) {
  // Che giấu các trường trông như bí mật hoặc thông tin cá nhân
  if (key === "apiKey") return "[ĐÃ ẨN]"
  if (key === "email") return value.replace(/(?<=.{2}).+(?=@)/, "***")
  return value
}

console.log(JSON.stringify(auditRecord, safeReplacer, 2))
// {
//   "requestId": "req_7d2e91",
//   "user": { "id": "usr_4421", "email": "ng.***@example.vn", "apiKey": "[ĐÃ ẨN]" },
//   "action": "update_billing",
//   "timestamp": "2026-03-10T14:22:00.000Z",
//   "durationMs": 87
// }
Lưu ý:Hàm replacer được gọi với this được đặt thành đối tượng chứa key hiện tại. Lần gọi đầu tiên truyền chuỗi rỗng làm key và toàn bộ giá trị đang được serialize làm value — trả về không thay đổi để tiếp tục với serialize bình thường.

Xử Lý Các Kiểu Không Thể Serialize

Không phải tất cả giá trị JavaScript đều ánh xạ gọn gàng sang JSON. Biết cách mỗi kiểu hoạt động giúp ngăn mất dữ liệu im lặng và lỗi runtime không mong đợi trong code production.

Date — Tự Động qua toJSON()

Đối tượng Date có phương thức toJSON() trả về chuỗi ISO 8601. JSON.stringify() gọi toJSON() tự động trước khi serialize, vì vậy không cần xử lý tùy chỉnh.

JavaScript — serialize 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"
// }

// Bất kỳ đối tượng nào có phương thức toJSON() đều được xử lý tương tự:
const custom = { toJSON: () => "custom-value", hidden: 42 }
JSON.stringify(custom) // '"custom-value"'

Class Tùy Chỉnh — Triển Khai toJSON()

Bất kỳ class nào cũng có thể triển khai phương thức toJSON() JSON.stringify() sẽ tự động gọi nó trong quá trình serialize. Cách này sạch hơn so với replacer toàn cục cho các kiểu domain xuất hiện khắp codebase.

JavaScript — toJSON() tùy chỉnh
class Money {
  constructor(amount, currency) {
    this.amount = amount
    this.currency = currency
  }
  toJSON() {
    // Được JSON.stringify tự động gọi
    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 }  // Serialize thành chuỗi đơn giản
}

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

JSON.stringify(invoice, null, 2)
// {
//   "invoiceId": "inv_8f2a91bc",
//   "subtotal": { "amount": 199, "currency": "VND", "formatted": "VND 199.00" },
//   "tax": { "amount": 15.92, "currency": "VND", "formatted": "VND 15.92" },
//   "issuedAt": "2026-03-10T14:22:00.000Z"
// }
Lưu ý:toJSON() được ưu tiên hơn hàm replacer. Nếu cả hai tồn tại, toJSON() chạy trước — replacer nhận giá trị đã được chuyển đổi, không phải instance class gốc.

BigInt — TypeError Không Có Replacer

JavaScript — replacer BigInt
// Cái này ném: TypeError: Do not know how to serialize a BigInt
// JSON.stringify({ sessionId: 9007199254741234n })

// Giải pháp: chuyển BigInt thành chuỗi trong replacer
function bigIntReplacer(_key, value) {
  return typeof value === 'bigint' ? value.toString() : value
}

const metrics = {
  requestCount: 9007199254741234n,  // vượt quá Number.MAX_SAFE_INTEGER
  service: "ingestion-worker",
  region: "us-east-1"
}

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

Tham Chiếu Vòng — TypeError Không Có Seen Set

JavaScript — replacer tham chiếu vòng
// Cái này ném: TypeError: Converting circular structure to JSON
// const node = { id: "n1" }; node.self = node; JSON.stringify(node)

// Giải pháp: theo dõi đối tượng đã thấy bằng 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: "gốc" }
const child  = { id: "node_child", parent }
parent.child = child  // vòng

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

// Thay thế: npm install flatted
// import { stringify } from 'flatted'
// stringify(parent)  // xử lý ref vòng native

Tham Khảo Tham Số JSON.stringify()

Cả ba tham số đều được hỗ trợ đầy đủ trong mọi runtime JavaScript hiện đại. Mặc định tạo ra JSON gọn một dòng — truyền tham số tường minh để có output dễ đọc.

Tham số
Kiểu
Mặc định
Mô tả
value
any
Giá trị cần serialize. Đối tượng, mảng, chuỗi, số, boolean và null được hỗ trợ tự nhiên.
replacer
function | Array<string | number> | null
null
Lọc hoặc biến đổi các cặp key/value. Array = danh sách trắng các key cần giữ. Function = được gọi cho mỗi cặp key/value.
space
number | string | null
null
Thụt lề. Số = số khoảng trắng mỗi cấp (tối đa 10). Chuỗi = ký tự thụt lề (ví dụ "\t"). null hoặc 0 = output gọn.

Định Dạng JSON từ File và Phản Hồi API

Trong Node.js (18+) bạn thường cần định dạng lại file config JSON hoặc in đẹp phản hồi API để debug. Cả hai mẫu đều dùng cách tiếp cận hai bước giống nhau: parse văn bản thô bằng JSON.parse(), sau đó serialize lại bằng JSON.stringify().

Đọc và Ghi Lại File Config JSON

Node.js 18+ — định dạng lại file 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('Config đã được định dạng lại thành công')
} catch (err) {
  console.error('Định dạng lại config thất bại:', err.message)
  // JSON.parse ném SyntaxError nếu file chứa JSON không hợp lệ
  // readFileSync ném ENOENT nếu file không tồn tại
}

Định Dạng Lại File Async (fs/promises)

Node.js 18+ — định dạng lại file async
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 }
}

// Sử dụng
const { keys } = await reformatJson('./config/feature-flags.json')
console.log(`Đã định dạng lại ${keys} key cấp cao nhất`)

In Đẹp JSON từ Phản Hồi fetch()

Khi xây dựng hoặc debug API client trong Node.js 18+ hoặc trình duyệt, in đẹp body phản hồi là cách nhanh nhất để hiểu server trả về gì. Mẫu chuẩn là response.json() (đối tượng đã parse) rồi JSON.stringify(). Nếu bạn cần chuỗi thô trước — ví dụ để tính hash hoặc log nguyên văn — dùng response.text() rồi JSON.parse().

JavaScript — fetch + in đẹp (Node.js 18+ hoặc trình duyệt)
// Mẫu 1: response.json() → in đẹp
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() khi cần chuỗi thô trước
// Mẫu 2: response.text() → parse → định dạng
// Hữu ích khi muốn log cả phản hồi thô VÀ in đẹp nó
async function inspectRawResponse(url) {
  const res = await fetch(url)
  const raw = await res.text()

  console.log('Độ dài phản hồi thô:', raw.length)
  try {
    const parsed = JSON.parse(raw)
    console.log('Đã định dạng:')
    console.log(JSON.stringify(parsed, null, 2))
  } catch {
    console.error('Phản hồi không phải JSON hợp lệ:', raw.slice(0, 200))
  }
}

In Đẹp từ Dòng Lệnh

Node.js có đủ khả năng để in đẹp JSON từ terminal mà không cần công cụ thêm. Những lệnh one-liner này hữu ích trong script CI, pipeline triển khai và alias shell. Để sử dụng tương tác nhanh hơn, cài jq — tiêu chuẩn de-facto để xử lý JSON trên dòng lệnh.

bash — in đẹp file JSON với Node.js
# In đẹp package.json dùng node -p (print)
node -p "JSON.stringify(require('./package.json'), null, 2)"

# In đẹp từ stdin (tương thích pipe, hoạt động trong CI)
echo '{"port":3000,"env":"production"}' | node -e "
  const d = require('fs').readFileSync(0, 'utf8')
  console.log(JSON.stringify(JSON.parse(d), null, 2))
"

# In đẹp phản hồi API đã lưu vào file
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 — các lựa chọn thay thế phổ quát
# Dự phòng Python (cài sẵn trên macOS và hầu hết distro Linux)
cat api-response.json | python3 -m json.tool

# jq — nhanh nhất và nhiều tính năng nhất (brew install jq / apt install jq)
cat api-response.json | jq .

# jq — in đẹp và lọc trong một bước
cat api-response.json | jq '.data.users[] | {id, email}'
Lưu ý:Khi chạy Node.js ở chế độ ESM (ví dụ với "type": "module" trong package.json), require() không có trong các lệnh one-liner. Dùng --input-type=module fs.readFileSync thay thế, hoặc chuyển sang node -e với đoạn CommonJS như minh họa ở trên.

Nếu bạn hoàn toàn không ở trong terminal — dán response từ Postman hoặc file log — Trình định dạng JSON của ToolDeck cho phép bạn dán, định dạng và sao chép trong một bước với tô sáng cú pháp và xác thực tích hợp.

Thay Thế Hiệu Năng Cao — fast-json-stringify

fast-json-stringify tạo ra hàm serializer chuyên dụng từ JSON Schema. Vì nó biết trước hình dạng của dữ liệu, nó có thể bỏ qua kiểm tra kiểu và dùng nối chuỗi thay vì đệ quy xuống — các benchmark thường cho thấy cải thiện throughput 2–5× so với JSON.stringify() trên các payload lớn, lặp đi lặp lại. Tôi dùng nó trong các route API tần suất cao khi chi phí serialize xuất hiện trong trace của profiler.

bash
npm install fast-json-stringify
JavaScript — fast-json-stringify cho event telemetry
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:    'eu-west-1'
}

const json = serializeTelemetryEvent(event)
// '{"eventId":"evt_3c7f9a2b","service":"checkout-api","severity":"warn",...}'
Lưu ý:fast-json-stringify được thiết kế cho serialization production của dữ liệu có cấu trúc — luôn tạo output gọn (không in đẹp). Để có output dễ đọc trong quá trình phát triển, dùng JSON.stringify(data, null, 2) như bình thường.

Output Terminal với Tô Sáng Cú Pháp

Hàm util.inspect() tích hợp của Node.js tạo ra output có màu, dễ đọc được tối ưu hóa cho hiển thị terminal. Nó xử lý tham chiếu vòng và BigInt native, và render đệ quy các đối tượng lồng nhau đến bất kỳ độ sâu nào. Output không phải JSON hợp lệ — nó dùng cú pháp JavaScript (ví dụ render function và Symbol thay vì bỏ qua), khiến nó lý tưởng cho script debug Node.js nhưng không phù hợp cho phản hồi API hoặc output file.

Node.js 18+ — util.inspect với màu sắc
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 → mở rộng tất cả cấp lồng nhau; colors: true → màu terminal ANSI
console.log(inspect(payload, { colors: true, depth: null }))
Cảnh báo:Đừng dùng util.inspect() cho JSON ghi vào file, gửi qua mạng hoặc lưu trong database. Output của nó không phải JSON hợp lệ và sẽ gây lỗi parse trong bất kỳ hệ thống downstream nào gọi JSON.parse() trên nó. Chỉ dùng cho debug terminal tương tác.

Làm Việc với File JSON Lớn

JSON.parse() tải toàn bộ file vào bộ nhớ trước khi parse — ổn với payload nhỏ, nhưng không thực tế với file trên 50–100 MB như export database, dump log ứng dụng hoặc batch phân tích. Với những trường hợp này, Node.js Streams và thư viện stream-json cho phép xử lý từng bản ghi mà không làm vỡ heap.

Phân Tích Streaming với stream-json

bash
npm install stream-json
Node.js 18+ — stream-json cho mảng lớn
import { pipeline } from 'stream/promises'
import { createReadStream } from 'fs'
import { parser } from 'stream-json'
import { streamArray } from 'stream-json/streamers/StreamArray.js'

// events.json = mảng hàng triệu đối tượng — không bao giờ tải hoàn toàn vào bộ nhớ
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 — Không Cần Phụ Thuộc Thêm

NDJSON (Newline Delimited JSON) lưu một đối tượng JSON mỗi dòng và phổ biến trong export Kafka, output BigQuery và pipeline log có cấu trúc. Module readline tích hợp của Node.js xử lý nó mà không cần package nào từ bên thứ ba.

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

// Định dạng: một đối tượng JSON mỗi dòng (log, export 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))
  }
}
Lưu ý:Chuyển từ JSON.parse() sang streaming khi file JSON vượt quá 50–100 MB hoặc khi xử lý stream không giới hạn (Kafka, pipeline log). Với NDJSON / JSON Lines, dùng readline — không cần phụ thuộc thêm.

Lỗi Phổ Biến

Bốn lỗi này xuất hiện liên tục trong code review và báo cáo lỗi production. Mỗi lỗi liên quan đến một hành vi tinh tế của JSON.stringify() dễ bỏ qua và khó debug sau thực tế.

Quên rằng giá trị undefined bị loại bỏ im lặng

Vấn đề: Các thuộc tính đối tượng có giá trị undefined bị bỏ qua hoàn toàn khỏi output JSON — không có cảnh báo hay lỗi. Điều này gây mất dữ liệu vô hình khi đối tượng có các trường tùy chọn.

Giải pháp: Dùng null cho các giá trị cố ý vắng mặt phải xuất hiện trong output đã serialize. Giữ undefined chỉ cho các trường nên được loại trừ khỏi JSON.

Before · JavaScript
After · JavaScript
const userProfile = {
  userId: "usr_4421",
  displayName: "Nguyễn Văn An",
  avatarUrl: undefined,   // sẽ biến mất im lặng
  bio: undefined          // sẽ biến mất im lặng
}

JSON.stringify(userProfile, null, 2)
// { "userId": "usr_4421", "displayName": "Nguyễn Văn An" }
// avatarUrl và bio đã biến mất — không có cảnh báo
const userProfile = {
  userId: "usr_4421",
  displayName: "Nguyễn Văn An",
  avatarUrl: null,   // cố ý vắng mặt — xuất hiện trong output
  bio: null          // cố ý vắng mặt — xuất hiện trong output
}

JSON.stringify(userProfile, null, 2)
// {
//   "userId": "usr_4421",
//   "displayName": "Nguyễn Văn An",
//   "avatarUrl": null,
//   "bio": null
// }
BigInt ném TypeError

Vấn đề: Truyền giá trị BigInt vào JSON.stringify() ném TypeError tại runtime. Đây là crash cứng, không phải bỏ qua im lặng — sẽ xuất hiện trong production nếu có trường số vượt quá Number.MAX_SAFE_INTEGER.

Giải pháp: Dùng hàm replacer chuyển đổi giá trị BigInt thành chuỗi trước khi serialize. Ngoài ra, chuyển đổi BigInt thành chuỗi hoặc Number ở tầng dữ liệu trước khi truyền cho JSON.stringify.

Before · JavaScript
After · JavaScript
const session = {
  sessionId: 9007199254741234n,  // literal 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"
// }
Crash do tham chiếu vòng

Vấn đề: Các đối tượng tham chiếu chính mình — phổ biến trong cây DOM, danh sách liên kết và một số result set ORM — ném TypeError khi truyền cho JSON.stringify(). Lỗi chỉ xảy ra tại thời điểm serialize, thường rất xa nơi tham chiếu vòng được tạo ra.

Giải pháp: Dùng hàm replacer với WeakSet để phát hiện và thay thế tham chiếu vòng, hoặc cài thư viện flatted như một replacement drop-in xử lý cấu trúc vòng native.

Before · JavaScript
After · JavaScript
const dept = { id: "dept_eng", name: "Kỹ thuật" }
const team = { id: "team_frontend", dept }
dept.teams = [team]  // vòng: 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: "Kỹ thuật" }
const team = { id: "team_frontend", dept }
dept.teams = [team]

// flatted xử lý ref vòng — lưu ý: output ở định dạng flatted, không phải JSON chuẩn
stringify(dept)

// Hoặc dùng replacer dựa trên WeakSet nếu cần output JSON chuẩn:
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)
Dùng space > 10 (bị giới hạn im lặng)

Vấn đề: Truyền giá trị space lớn hơn 10 cho JSON.stringify() không ném lỗi — giá trị bị giới hạn im lặng ở 10. Lập trình viên mong đợi 20 khoảng trắng mỗi mức thụt lề cho cấu trúc lồng sâu sẽ chỉ nhận được 10, dẫn đến định dạng bất ngờ trong file được tạo ra.

Giải pháp: Thụt lề tối đa là 10 khoảng trắng. Với cấu trúc sâu, ưu tiên thụt lề 2 khoảng trắng (quy ước phổ biến nhất trong dự án JavaScript) và dựa vào editor có thể gập lại để điều hướng.

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

// Mong đợi thụt lề 20 khoảng trắng — nhưng space bị giới hạn ở 10
JSON.stringify(deepConfig, null, 20)
// Output giống hệt JSON.stringify(deepConfig, null, 10)
// Không có lỗi, không có cảnh báo — bị cắt ngắn im lặng
const deepConfig = { server: { tls: { certs: { primary: "/etc/ssl/api.pem" } } } }

// Dùng 2 (hầu hết dự án) hoặc 4 khoảng trắng — không bao giờ vượt 10
JSON.stringify(deepConfig, null, 2)
// {
//   "server": {
//     "tls": {
//       "certs": {
//         "primary": "/etc/ssl/api.pem"
//       }
//     }
//   }
// }

JSON.stringify so với Các Lựa Chọn Thay Thế — So Sánh Nhanh

Các tình huống khác nhau cần công cụ khác nhau. JSON.stringify với replacer bao gồm hầu hết các trường hợp production mà không cần phụ thuộc. util.inspect là lựa chọn phù hợp cho debug terminal nhanh khi cần output có màu và không cần JSON hợp lệ. fast-json-stringify đáng đầu tư ở các route thông lượng cao khi profiling cho thấy chi phí serialize; với mọi thứ khác thì overhead duy trì schema không đáng.

Phương thức
Output đẹp
JSON hợp lệ
Non-ASCII
Kiểu tùy chỉnh
Tham chiếu vòng
Cần cài đặt
JSON.stringify
⚠️ qua replacer
✗ (ném lỗi)
Không
JSON.stringify + replacer
✅ kiểm soát hoàn toàn
Không
util.inspect
✅ native
Không (tích hợp Node)
fast-json-stringify
❌ chỉ schema
npm install
flatted
✗ (định dạng tùy chỉnh)
✅ chỉ circular
npm install
jq (CLI)
N/A
N/A
Cài hệ thống

Câu Hỏi Thường Gặp

Làm thế nào để in đẹp JSON trong JavaScript?

Gọi JSON.stringify(data, null, 2) — đối số thứ ba kiểm soát thụt lề. Truyền 2 hoặc 4 cho khoảng trắng, hoặc "\t" cho tab. Không cần import hay cài đặt: JSON là đối tượng toàn cục trong mọi môi trường JavaScript, bao gồm trình duyệt và 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
// }

Tham số `space` trong JSON.stringify() làm gì?

Tham số space kiểm soát thụt lề trong output. Truyền một số (1–10) cho số khoảng trắng đó mỗi cấp, hoặc một chuỗi như "\t" để dùng ký tự tab. Các giá trị trên 10 bị giới hạn im lặng ở 10. Truyền null, 0 hoặc bỏ qua tham số sẽ tạo JSON gọn một dòng.

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

JSON.stringify(data, null, 2)   // thụt lề 2 khoảng trắng
JSON.stringify(data, null, 4)   // thụt lề 4 khoảng trắng
JSON.stringify(data, null, '\t') // thụt lề tab
JSON.stringify(data)            // gọn: {"service":"payments","version":3,"active":true}

Tại sao JSON.stringify() trả về undefined cho một số giá trị?

JSON.stringify âm thầm bỏ qua các thuộc tính đối tượng có giá trị là undefined, function hoặc Symbol — những kiểu này không có biểu diễn trong JSON. Nếu chính giá trị cấp cao nhất là undefined, hàm trả về undefined (không phải chuỗi "undefined"). Dùng null thay vì undefined cho các trường tùy chọn phải xuất hiện trong output.

JavaScript
const event = {
  traceId: "tr_9a2f",
  handler: () => {},        // function — bị bỏ qua
  requestId: undefined,     // undefined — bị bỏ qua
  sessionId: Symbol("s"),   // Symbol — bị bỏ qua
  status: "ok"
}
JSON.stringify(event, null, 2)
// { "traceId": "tr_9a2f", "status": "ok" }

Làm thế nào để xử lý đối tượng Date khi định dạng JSON?

Đối tượng Date có phương thức toJSON() tích hợp trả về chuỗi ISO 8601, vì vậy JSON.stringify xử lý chúng tự động. Bạn không cần replacer tùy chỉnh cho ngày tháng — giá trị được serialize sẽ là một chuỗi như "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
// }

Làm thế nào để định dạng chuỗi JSON (không phải đối tượng) trong JavaScript?

Parse chuỗi trước bằng JSON.parse(), sau đó serialize lại bằng JSON.stringify(). Hai lần gọi có thể được xâu chuỗi trong một dòng để debug nhanh.

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

Có thể dùng JSON.stringify() trong trình duyệt không?

Có. JSON là global tích hợp trong mọi trình duyệt hiện đại từ IE8 — không cần thẻ script hay import. Mở bảng điều khiển DevTools và gọi JSON.stringify() trực tiếp. Nó hoạt động giống hệt phiên bản Node.js, với cùng chữ ký tham số và cùng giới hạn về BigInt và tham chiếu vòng.

JavaScript
// Hoạt động trên Chrome, Firefox, Safari, Edge — không cần import
const payload = { userId: "usr_7b3c", action: "checkout", cart: ["SKU-001", "SKU-002"] }
copy(JSON.stringify(payload, null, 2)) // copy() là helper của DevTools

JavaScript cho bạn toàn quyền kiểm soát — hàm replacer, toJSON() tùy chỉnh, xử lý file lớn trong Node.js. Khi bạn chỉ cần kiểm tra hoặc chia sẻ một đoạn code đã định dạng, Trình định dạng JSON của ToolDeck là con đường nhanh nhất: dán JSON của bạn và nhận kết quả được định dạng, tô sáng mà không cần bất kỳ thiết lập môi trường nào.

Công Cụ Liên Quan

Cũng có sẵn trong: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 WebbNgười đánh giá kỹ thuật

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.