ToolDeck

JSON Formatter JavaScript — JSON.stringify()

·Front-end & Node.js Developer·ตรวจสอบโดยMarcus Webb·เผยแพร่เมื่อ

ใช้ จัดรูปแบบและตกแต่ง JSON ฟรีโดยตรงในเบราว์เซอร์ของคุณ — ไม่ต้องติดตั้ง

ลอง จัดรูปแบบและตกแต่ง JSON ออนไลน์ →

เวลา debug API response ใน Node.js สิ่งที่ทำให้ผมช้าลงเสมอคือกำแพง JSON แบบอัด — แค่เรียก JSON.stringify(data, null, 2) ครั้งเดียว โครงสร้างก็อ่านได้ทันที ในการ format JSON ใน JavaScript นั้น ไม่ต้องการอะไรนอกจาก runtime: JSON.stringify มีอยู่ใน every browser และ Node.js environment โดยไม่ต้องติดตั้ง ถ้าต้องการผลลัพธ์รวดเร็วโดยไม่ต้องเขียนโค้ด JSON Formatter ของ ToolDeck ทำได้ทันที คู่มือนี้ครอบคลุมทุกเรื่องเชิงปฏิบัติ: พารามิเตอร์ space, replacer array และ function, การจัดการ Date, BigInt และ circular reference, การอ่านเขียนไฟล์ JSON ใน Node.js (18+), การ pretty-print จาก CLI และ library fast-json-stringify สำหรับ serialization ใน production

  • JSON.stringify(data, null, 2) มีอยู่ใน every browser และ Node.js — ไม่ต้องติดตั้ง
  • พารามิเตอร์ replacer รับ array (key whitelist) หรือ function (แปลงค่า) — ใช้เพื่อซ่อน field ที่ sensitive
  • Date object serialize อัตโนมัติผ่าน toJSON() → ISO 8601 string; BigInt โยน TypeError และต้องใช้ replacer กำหนดเอง
  • Circular reference โยน TypeError — แก้ด้วย seen Set ใน replacer function หรือใช้ library flatted
  • สำหรับ CLI pretty-printing ใช้ node -p "JSON.stringify(require('./file.json'),null,2)" — ไม่ต้องใช้เครื่องมือเพิ่มเติม

JSON Formatting คืออะไร?

การ format JSON (เรียกอีกอย่างว่า pretty-printing) แปลง JSON string แบบอัดกระชับ ให้เป็น layout ที่มนุษย์อ่านได้โดยมีการเยื้องและขึ้นบรรทัดใหม่ที่สม่ำเสมอ ข้อมูล ด้านในเหมือนกันทุกประการ — เปลี่ยนแค่ whitespace JSON แบบกระชับเหมาะกับการส่งผ่าน network ที่ทุก byte มีค่า ส่วน JSON ที่ format แล้วเหมาะกับการ debug, code review และการตรวจสอบ log ฟังก์ชัน 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 Formatter ในตัว

JSON.stringify() เป็น global function ในทุก JavaScript environment — browser, Node.js, Deno, Bun — โดยไม่ต้อง import อาร์กิวเมนต์ที่สาม space ควบคุมการเยื้อง: ส่งตัวเลขสำหรับจำนวนช่องว่างต่อระดับ หรือ string '\t' สำหรับ tab ไม่ส่ง (หรือส่ง null) จะได้ output แบบกระชับในบรรทัดเดียว

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 ช่องว่าง) หรือ string การส่ง tab character จะได้ output ที่ editor และ diff tool หลายตัวชอบ คุณยังรวมพารามิเตอร์ทั้งสามได้ — นี่คือ pattern จริงที่ ผมใช้เมื่อเขียน JSON ที่ format แล้วลงไฟล์ config:

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)

// เยื้อง tab (ที่นิยมของ linter และ config tool บางตัว)
JSON.stringify(telemetryEvent, null, '\t')

// กระชับ — ไม่มี whitespace (สำหรับส่งผ่าน network)
JSON.stringify(telemetryEvent)
// {"eventId":"evt_3c7f9a2b","service":"checkout-api",...}
หมายเหตุ:ค่า undefined, function และ Symbol จะถูกละเว้นจาก output โดยเงียบๆ ถ้าค่าของ property เป็น undefined key นั้น จะไม่ปรากฏใน serialized string เลย — นี่คือแหล่งที่มาของ bug ที่พบบ่อยเมื่อ log object ที่มี field ที่ไม่บังคับ

Replacer Function — กรองและแปลง Output

อาร์กิวเมนต์ที่สองของ JSON.stringify() คือ replacer มีสองรูปแบบ: เป็น array ที่ whitelist key เฉพาะ หรือเป็น function ที่ถูกเรียกสำหรับทุกคู่ key/value และสามารถกรอง แปลง หรือซ่อนค่าได้ ผมใช้รูปแบบ array เมื่อต้องการ subset เร็วๆ และรูปแบบ function เมื่อต้องซ่อนข้อมูลที่ sensitive ก่อน log

Array Replacer — Whitelist Key เฉพาะ

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

// รวมเฉพาะ field ที่ปลอดภัยใน log output
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 ถูกยกเว้น

Function Replacer — แปลงค่า

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

function safeReplacer(key, value) {
  // ซ่อน field ที่ดูเหมือน secret หรือข้อมูลส่วนตัว
  if (key === "apiKey") return "[ซ่อนไว้]"
  if (key === "email") return value.replace(/(?<=.{2}).+(?=@)/, "***")
  return value
}

console.log(JSON.stringify(auditRecord, safeReplacer, 2))
// {
//   "requestId": "req_7d2e91",
//   "user": { "id": "usr_4421", "email": "so.***@example.th", "apiKey": "[ซ่อนไว้]" },
//   "action": "update_billing",
//   "timestamp": "2026-03-10T14:22:00.000Z",
//   "durationMs": 87
// }
หมายเหตุ:Replacer function ถูกเรียกโดยมี this ชี้ไปยัง object ที่มี key ปัจจุบัน การเรียกครั้งแรกส่ง empty string เป็น key และค่าทั้งหมดที่กำลัง serialize เป็น value — คืนค่าโดยไม่เปลี่ยนแปลงเพื่อดำเนินการ serialize ตามปกติ

การจัดการชนิดที่ Serialize ไม่ได้

ไม่ใช่ทุกค่าใน JavaScript จะ map ลง JSON ได้อย่างราบรื่น การรู้ว่าแต่ละชนิดทำงาน อย่างไรช่วยป้องกันการสูญเสียข้อมูลแบบเงียบๆ และ runtime error ที่ไม่คาดคิดใน production code

Date — อัตโนมัติผ่าน toJSON()

Object Date มี method toJSON() ที่คืนค่า ISO 8601 string JSON.stringify() เรียก toJSON() อัตโนมัติก่อน serialize ดังนั้นไม่จำเป็นต้องจัดการเองเป็นพิเศษ

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

// Object ที่มี method toJSON() ใดๆ ก็ได้รับการปฏิบัติเหมือนกัน:
const custom = { toJSON: () => "custom-value", hidden: 42 }
JSON.stringify(custom) // '"custom-value"'

Custom Class — Implement toJSON()

Class ใดๆ สามารถ implement method toJSON() และ JSON.stringify() จะเรียกมันอัตโนมัติระหว่าง serialize วิธีนี้สะอาดกว่า global replacer สำหรับ domain type ที่ปรากฏทั่วทั้ง codebase

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 }  // Serialize เป็น plain string
}

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

JSON.stringify(invoice, null, 2)
// {
//   "invoiceId": "inv_8f2a91bc",
//   "subtotal": { "amount": 199, "currency": "THB", "formatted": "THB 199.00" },
//   "tax": { "amount": 15.92, "currency": "THB", "formatted": "THB 15.92" },
//   "issuedAt": "2026-03-10T14:22:00.000Z"
// }
หมายเหตุ:toJSON() มีความสำคัญเหนือ replacer function ถ้ามีทั้งสองอย่าง toJSON() ทำงานก่อน — replacer ได้รับค่าที่แปลงแล้ว ไม่ใช่ class instance เดิม

BigInt — TypeError โดยไม่มี Replacer

JavaScript — BigInt replacer
// อันนี้โยน: TypeError: Do not know how to serialize a BigInt
// JSON.stringify({ sessionId: 9007199254741234n })

// วิธีแก้: แปลง BigInt เป็น string ใน replacer
function bigIntReplacer(_key, value) {
  return typeof value === 'bigint' ? value.toString() : value
}

const metrics = {
  requestCount: 9007199254741234n,  // เกิน 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"
// }

Circular Reference — TypeError โดยไม่มี Seen Set

JavaScript — circular reference replacer
// อันนี้โยน: TypeError: Converting circular structure to JSON
// const node = { id: "n1" }; node.self = node; JSON.stringify(node)

// วิธีแก้: ติดตาม object ที่เคยเห็นด้วย 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: "ราก" }
const child  = { id: "node_child", parent }
parent.child = child  // circular

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

// อีกทางเลือก: npm install flatted
// import { stringify } from 'flatted'
// stringify(parent)  // จัดการ circular ref แบบ native

อ้างอิงพารามิเตอร์ JSON.stringify()

ทั้งสามพารามิเตอร์รองรับเต็มรูปแบบในทุก JavaScript runtime สมัยใหม่ ค่าเริ่มต้น ผลิต JSON แบบกระชับในบรรทัดเดียว — ส่งพารามิเตอร์อย่างชัดเจนเพื่อ output ที่อ่านง่าย

พารามิเตอร์
ชนิด
ค่าเริ่มต้น
คำอธิบาย
value
any
ค่าที่ต้องการ serialize รองรับ Object, Array, String, Number, Boolean และ null โดยตรง
replacer
function | Array<string | number> | null
null
กรองหรือแปลงคู่ key/value Array = รายการขาวของ key ที่ต้องการรวม Function = ถูกเรียกสำหรับทุกคู่ key/value
space
number | string | null
null
การเยื้อง ตัวเลข = ช่องว่างต่อระดับ (สูงสุด 10) String = ตัวอักษรเยื้อง (เช่น "\t") null หรือ 0 = output แบบกระชับ

Format JSON จากไฟล์และ API Response

ใน Node.js (18+) คุณมักต้อง reformat ไฟล์ config JSON หรือ pretty-print API response เพื่อ debug ทั้งสอง pattern ใช้แนวทางสองขั้นตอนเหมือนกัน: parse ข้อความดิบด้วย JSON.parse(), จากนั้น serialize ใหม่ด้วย JSON.stringify()

อ่านและเขียนไฟล์ Config JSON ใหม่

Node.js 18+ — reformat ไฟล์ 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('Reformat config สำเร็จ')
} catch (err) {
  console.error('Reformat config ไม่สำเร็จ:', err.message)
  // JSON.parse โยน SyntaxError ถ้าไฟล์มี JSON ที่ไม่ถูกต้อง
  // readFileSync โยน ENOENT ถ้าไม่มีไฟล์
}

Async File Reformat (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(`Reformat ${keys} key ระดับบนสุดแล้ว`)

Pretty Print JSON จาก fetch() Response

เมื่อ build หรือ debug API client ใน Node.js 18+ หรือ browser การ pretty-print response body คือวิธีที่เร็วที่สุดในการทำความเข้าใจว่า server ส่งอะไรกลับมา Pattern มาตรฐานคือ response.json() (object ที่ parse แล้ว) แล้วตามด้วย JSON.stringify()ถ้าต้องการ raw string ก่อน — เช่น เพื่อคำนวณ hash หรือ log ตามต้นฉบับ — ใช้ response.text() แล้วค่อย JSON.parse()

JavaScript — fetch + pretty print (Node.js 18+ หรือ browser)
// Pattern 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() เมื่อต้องการ raw string ก่อน
// Pattern 2: response.text() → parse → format
// มีประโยชน์เมื่อต้องการ log raw response และ pretty-print ด้วย
async function inspectRawResponse(url) {
  const res = await fetch(url)
  const raw = await res.text()

  console.log('ความยาว raw response:', raw.length)
  try {
    const parsed = JSON.parse(raw)
    console.log('ที่ format แล้ว:')
    console.log(JSON.stringify(parsed, null, 2))
  } catch {
    console.error('Response ไม่ใช่ JSON ที่ถูกต้อง:', raw.slice(0, 200))
  }
}

Pretty Printing จาก Command Line

Node.js มีความสามารถเพียงพอในการ pretty-print JSON จาก terminal โดยไม่ต้องใช้ เครื่องมือเพิ่มเติม one-liner เหล่านี้มีประโยชน์ใน CI script, deployment pipeline และ shell alias สำหรับการใช้งาน interactive ที่เร็วกว่า ติดตั้ง jq — มาตรฐาน de-facto สำหรับการจัดการ JSON บน command line

bash — pretty print ไฟล์ JSON ด้วย 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 response ที่บันทึกไว้ในไฟล์
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 fallback (ติดตั้งล่วงหน้าบน macOS และ Linux distro ส่วนใหญ่)
cat api-response.json | python3 -m json.tool

# jq — เร็วที่สุดและมีฟีเจอร์มากที่สุด (brew install jq / apt install jq)
cat api-response.json | jq .

# jq — pretty-print และ filter ในขั้นตอนเดียว
cat api-response.json | jq '.data.users[] | {id, email}'
หมายเหตุ:เมื่อ run Node.js ในโหมด ESM (เช่น มี "type": "module" ใน package.json) require() ไม่สามารถใช้ใน one-liner ได้ ใช้ --input-type=module และ fs.readFileSync แทน หรือเปลี่ยนไปใช้ node -e กับ CommonJS snippet ดังที่แสดงไว้ข้างต้น

ถ้าคุณไม่ได้อยู่ใน terminal เลย — วาง response จาก Postman หรือไฟล์ log — JSON Formatter ของ ToolDeck ช่วยให้คุณวาง, format และคัดลอกได้ในขั้นตอนเดียว พร้อม syntax highlighting และ validation ในตัว

ทางเลือกที่มีประสิทธิภาพสูง — fast-json-stringify

fast-json-stringify สร้าง serializer function เฉพาะจาก JSON Schema เนื่องจากรู้ shape ของข้อมูลล่วงหน้า จึงข้าม type checking ได้และใช้ string concatenation แทน recursive descent — benchmark มักแสดงการปรับปรุง throughput 2–5× เมื่อเทียบกับ JSON.stringify() บน payload ขนาดใหญ่ที่ซ้ำๆ ผมใช้มันใน API route ที่มีความถี่สูงที่ serialization cost ปรากฏใน profiler trace

bash
npm install fast-json-stringify
JavaScript — fast-json-stringify สำหรับ telemetry event
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",...}'
หมายเหตุ:fast-json-stringify ออกแบบมาสำหรับ production serialization ของ structured data — ผลิต output แบบกระชับเสมอ (ไม่มี pretty-printing) สำหรับ output ที่มนุษย์อ่านได้ระหว่างพัฒนา ใช้ JSON.stringify(data, null, 2) ตามปกติ

Terminal Output พร้อม Syntax Highlighting

ฟังก์ชัน util.inspect() ในตัวของ Node.js ผลิต output ที่มีสีและอ่านได้สำหรับมนุษย์ที่ optimize สำหรับ terminal display จัดการ circular reference และ BigInt แบบ native และ render object ที่ซ้อนกันแบบ recursive ไม่ว่าจะลึกแค่ไหน output ไม่ใช่ JSON ที่ถูกต้อง — ใช้ syntax JavaScript (เช่น render function และ Symbol แทนที่จะละเว้น) ซึ่งทำให้เหมาะสำหรับ Node.js debug script แต่ไม่เหมาะสำหรับ API response หรือ file output

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 → ขยายทุก level ที่ซ้อนกัน; colors: true → สี terminal ANSI
console.log(inspect(payload, { colors: true, depth: null }))
คำเตือน:อย่าใช้ util.inspect() สำหรับ JSON ที่เขียนลงไฟล์ ส่งผ่าน network หรือเก็บใน database output ไม่ใช่ JSON ที่ถูกต้องและจะทำให้เกิด parse error ในระบบ downstream ที่เรียก JSON.parse() กับมัน ใช้สำหรับ interactive terminal debugging เท่านั้น

การทำงานกับไฟล์ JSON ขนาดใหญ่

JSON.parse() โหลดไฟล์ทั้งหมดเข้า memory ก่อน parse — ไม่มีปัญหาสำหรับ payload ขนาดเล็ก แต่ไม่ เหมาะสมกับไฟล์ที่เกิน 50–100 MB เช่น database export, application log dump หรือ analytics batch สำหรับกรณีเหล่านี้ Node.js Streams และ library stream-json ให้คุณประมวลผล record ทีละรายการโดยไม่ทำให้ heap เต็ม

Streaming Parsing ด้วย stream-json

bash
npm install stream-json
Node.js 18+ — stream-json สำหรับ array ขนาดใหญ่
import { pipeline } from 'stream/promises'
import { createReadStream } from 'fs'
import { parser } from 'stream-json'
import { streamArray } from 'stream-json/streamers/StreamArray.js'

// events.json = array ของ object หลายล้านรายการ — ไม่เคยโหลดเต็มเข้า memory
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 — ไม่ต้อง Dependencies เพิ่ม

NDJSON (Newline Delimited JSON) เก็บ JSON object หนึ่งรายการต่อบรรทัดและพบได้บ่อย ใน Kafka export, BigQuery output และ structured log pipeline โมดูล readline ในตัวของ Node.js จัดการได้โดยไม่ต้องใช้ package ภายนอก

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

// Format: JSON object หนึ่งรายการต่อบรรทัด (log, Kafka export, 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() เป็น streaming เมื่อไฟล์ JSON เกิน 50–100 MB หรือเมื่อประมวลผล stream ที่ไม่มีขอบเขต (Kafka, log pipeline) สำหรับ NDJSON / JSON Lines ใช้ readline — ไม่ต้อง dependencies เพิ่มเติม

ข้อผิดพลาดที่พบบ่อย

ข้อผิดพลาดสี่อย่างเหล่านี้ปรากฏซ้ำๆ ใน code review และรายงาน bug ใน production แต่ละอย่างเกี่ยวข้องกับพฤติกรรมละเอียดของ JSON.stringify() ที่มองข้ามได้ง่ายและ debug ยากในภายหลัง

ลืมว่าค่า undefined ถูกละเว้นโดยเงียบๆ

ปัญหา: Property ของ object ที่มีค่าเป็น undefined ถูกละเว้นทั้งหมดจาก JSON output — ไม่มีคำเตือนหรือ error สิ่งนี้ทำให้เกิดการสูญเสียข้อมูลที่มองไม่เห็นเมื่อ object มี field ที่ไม่บังคับ

วิธีแก้: ใช้ null สำหรับค่าที่ตั้งใจว่าง่ที่ต้องปรากฏใน output ที่ serialize แล้ว สงวน undefined ไว้สำหรับ field ที่ควรถูกยกเว้นจาก 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,   // ตั้งใจว่าง — ปรากฏใน output
  bio: null          // ตั้งใจว่าง — ปรากฏใน output
}

JSON.stringify(userProfile, null, 2)
// {
//   "userId": "usr_4421",
//   "displayName": "สมชาย ใจดี",
//   "avatarUrl": null,
//   "bio": null
// }
BigInt โยน TypeError

ปัญหา: การส่งค่า BigInt ให้ JSON.stringify() โยน TypeError ที่ runtime นี่คือ crash ที่รุนแรง ไม่ใช่การละเว้นแบบเงียบๆ — จะปรากฏใน production ถ้า field ตัวเลขใดๆ เกิน Number.MAX_SAFE_INTEGER

วิธีแก้: ใช้ replacer function ที่แปลงค่า BigInt เป็น string ก่อน serialize หรือแปลง BigInt เป็น string หรือ Number ที่ data layer ก่อนส่งให้ JSON.stringify

Before · JavaScript
After · JavaScript
const session = {
  sessionId: 9007199254741234n,  // BigInt literal
  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"
// }
Circular reference crash

ปัญหา: Object ที่อ้างอิงตัวเอง — พบบ่อยใน DOM tree, linked list และ ORM result set บางตัว — โยน TypeError เมื่อส่งให้ JSON.stringify() error เกิดขึ้นเฉพาะตอน serialize มักอยู่ห่างมากจากที่สร้าง circular reference

วิธีแก้: ใช้ replacer function กับ WeakSet เพื่อตรวจจับและแทนที่ circular reference หรือติดตั้ง library flatted เป็น drop-in replacement ที่จัดการ circular structure แบบ native

Before · JavaScript
After · JavaScript
const dept = { id: "dept_eng", name: "วิศวกรรม" }
const team = { id: "team_frontend", dept }
dept.teams = [team]  // circular: 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 จัดการ circular ref — หมายเหตุ: output อยู่ใน flatted format ไม่ใช่ JSON มาตรฐาน
stringify(dept)

// หรือใช้ replacer แบบ WeakSet ถ้าต้องการ output 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() ไม่โยน error — ค่าถูกจำกัดที่ 10 โดยเงียบๆ developer ที่คาดหวัง 20 ช่องว่างต่อ level สำหรับการ nesting ลึกๆ จะได้รับเพียง 10 ทำให้ format ใน generated file ไม่เป็นไปตามที่คาด

วิธีแก้: การเยื้องสูงสุดคือ 10 ช่องว่าง สำหรับโครงสร้างลึก ใช้การเยื้อง 2 ช่องว่าง (convention ที่พบบ่อยที่สุดในโปรเจกต์ JavaScript) และพึ่ง editor แบบ collapsible สำหรับการนำทาง

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

// คาดหวังการเยื้อง 20 ช่องว่าง — แต่ space ถูกจำกัดที่ 10
JSON.stringify(deepConfig, null, 20)
// Output เหมือนกับ JSON.stringify(deepConfig, null, 10)
// ไม่มี error ไม่มีคำเตือน — ถูกตัดทอนโดยเงียบๆ
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 เทียบกับทางเลือกอื่น — เปรียบเทียบเร็ว

สถานการณ์ต่างๆ ต้องการเครื่องมือต่างกัน JSON.stringify กับ replacer ครอบคลุม production use case ส่วนใหญ่โดยไม่มี dependencies util.inspect เป็นตัวเลือกที่ถูกต้องสำหรับ terminal debug รวดเร็วเมื่อต้องการ output ที่มีสีและ ไม่ต้องการ JSON ที่ถูกต้อง fast-json-stringify คุ้มค่าใน route ที่มี throughput สูงเมื่อ profiling แสดง serialization cost ส่วนทุก อย่างอื่น overhead ของการดูแล schema ไม่คุ้มค่า

วิธีการ
Output สวย
JSON ถูกต้อง
Non-ASCII
ชนิดกำหนดเอง
Circular Refs
ต้องติดตั้ง
JSON.stringify
⚠️ ผ่าน replacer
✗ (โยน error)
ไม่
JSON.stringify + replacer
✅ ควบคุมได้เต็มที่
ไม่
util.inspect
✅ native
ไม่ (Node built-in)
fast-json-stringify
❌ schema เท่านั้น
npm install
flatted
✗ (รูปแบบเฉพาะ)
✅ circular เท่านั้น
npm install
jq (CLI)
N/A
N/A
ติดตั้งในระบบ

คำถามที่พบบ่อย

จะพิมพ์ JSON ให้สวยใน JavaScript ได้อย่างไร?

เรียก JSON.stringify(data, null, 2) — อาร์กิวเมนต์ที่สามควบคุมการเยื้อง ส่ง 2 หรือ 4 สำหรับช่องว่าง หรือ "\t" สำหรับ tab ไม่ต้อง import หรือติดตั้ง: JSON คือ global object ในทุก JavaScript environment รวมถึงเบราว์เซอร์และ 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 ควบคุมการเยื้องใน output ส่งตัวเลข (1–10) สำหรับจำนวนช่องว่างต่อระดับ หรือ string เช่น "\t" เพื่อใช้ tab ค่าที่เกิน 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') // เยื้อง tab
JSON.stringify(data)            // กระชับ: {"service":"payments","version":3,"active":true}

ทำไม JSON.stringify() ถึงคืนค่า undefined สำหรับบางค่า?

JSON.stringify จะละเว้น property ของ object ที่มีค่าเป็น undefined, function หรือ Symbol โดยเงียบๆ — ชนิดเหล่านี้ไม่มีการแทนค่าใน JSON หากค่าระดับบนสุดเองเป็น undefined ฟังก์ชันจะคืนค่า undefined (ไม่ใช่ string "undefined") ใช้ null แทน undefined สำหรับ field ที่ไม่บังคับแต่ต้องปรากฏใน output

JavaScript
const event = {
  traceId: "tr_9a2f",
  handler: () => {},        // function — ถูกละเว้น
  requestId: undefined,     // undefined — ถูกละเว้น
  sessionId: Symbol("s"),   // Symbol — ถูกละเว้น
  status: "ok"
}
JSON.stringify(event, null, 2)
// { "traceId": "tr_9a2f", "status": "ok" }

จะจัดการ Date object เมื่อ format JSON ได้อย่างไร?

Date object มี method toJSON() ในตัวที่คืนค่า string ISO 8601 ดังนั้น JSON.stringify จัดการได้อัตโนมัติ ไม่จำเป็นต้องใช้ replacer กำหนดเองสำหรับวันที่ — ค่าที่ serialize แล้วจะเป็น string เช่น "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
// }

จะ format JSON string (ไม่ใช่ object) ใน JavaScript ได้อย่างไร?

parse string ก่อนด้วย JSON.parse() แล้วค่อย serialize ใหม่ด้วย JSON.stringify() สามารถเชื่อมสองการเรียกในบรรทัดเดียวเพื่อ debug อย่างรวดเร็ว

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 เป็น global ในตัวในทุกเบราว์เซอร์สมัยใหม่ตั้งแต่ IE8 — ไม่ต้อง script tag หรือ import เปิด DevTools console แล้วเรียก JSON.stringify() ได้เลย ทำงานเหมือนกันกับเวอร์ชัน Node.js ทุกประการ รวมถึง signature พารามิเตอร์และข้อจำกัดเดียวกันเกี่ยวกับ BigInt และ circular reference

JavaScript
// ใช้งานได้บน Chrome, Firefox, Safari, Edge — ไม่ต้อง import
const payload = { userId: "usr_7b3c", action: "checkout", cart: ["SKU-001", "SKU-002"] }
copy(JSON.stringify(payload, null, 2)) // copy() เป็น helper ของ DevTools

JavaScript ให้การควบคุมอย่างสมบูรณ์ — replacer function, toJSON() แบบกำหนดเอง, การประมวลผลไฟล์ขนาดใหญ่ใน Node.js เมื่อต้องการเพียงตรวจสอบหรือแชร์ snippet ที่ format แล้ว JSON Formatter ของ ToolDeck คือทางที่เร็วที่สุด: วาง JSON แล้วรับผลลัพธ์ที่ format และ highlight แล้วโดยไม่ต้องตั้งค่า environment ใด ๆ

เครื่องมือที่เกี่ยวข้อง

มีให้ในภาษาอื่นด้วย: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.