JSON Formatter JavaScript — JSON.stringify()
ใช้ จัดรูปแบบและตกแต่ง 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
{"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 แบบกระชับในบรรทัดเดียว
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:
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 เฉพาะ
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 — แปลงค่า
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
// }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 ดังนั้นไม่จำเป็นต้องจัดการเองเป็นพิเศษ
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
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
// อันนี้โยน: 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
// อันนี้โยน: 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 ที่อ่านง่าย
Format JSON จากไฟล์และ API Response
ใน Node.js (18+) คุณมักต้อง reformat ไฟล์ config JSON หรือ pretty-print API response เพื่อ debug ทั้งสอง pattern ใช้แนวทางสองขั้นตอนเหมือนกัน: parse ข้อความดิบด้วย JSON.parse(), จากนั้น serialize ใหม่ด้วย JSON.stringify()
อ่านและเขียนไฟล์ Config 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('Reformat config สำเร็จ')
} catch (err) {
console.error('Reformat config ไม่สำเร็จ:', err.message)
// JSON.parse โยน SyntaxError ถ้าไฟล์มี JSON ที่ไม่ถูกต้อง
// readFileSync โยน ENOENT ถ้าไม่มีไฟล์
}Async File Reformat (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(`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()
// 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')// 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
# 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)))
"# 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}'"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
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: '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
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
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 = 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 ภายนอก
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 ยากในภายหลัง
ปัญหา: Property ของ object ที่มีค่าเป็น undefined ถูกละเว้นทั้งหมดจาก JSON output — ไม่มีคำเตือนหรือ error สิ่งนี้ทำให้เกิดการสูญเสียข้อมูลที่มองไม่เห็นเมื่อ object มี field ที่ไม่บังคับ
วิธีแก้: ใช้ null สำหรับค่าที่ตั้งใจว่าง่ที่ต้องปรากฏใน output ที่ serialize แล้ว สงวน undefined ไว้สำหรับ field ที่ควรถูกยกเว้นจาก JSON เท่านั้น
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 ให้ JSON.stringify() โยน TypeError ที่ runtime นี่คือ crash ที่รุนแรง ไม่ใช่การละเว้นแบบเงียบๆ — จะปรากฏใน production ถ้า field ตัวเลขใดๆ เกิน Number.MAX_SAFE_INTEGER
วิธีแก้: ใช้ replacer function ที่แปลงค่า BigInt เป็น string ก่อน serialize หรือแปลง BigInt เป็น string หรือ Number ที่ data layer ก่อนส่งให้ JSON.stringify
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 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"
// }ปัญหา: 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
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 JSONimport { 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 ให้ JSON.stringify() ไม่โยน error — ค่าถูกจำกัดที่ 10 โดยเงียบๆ developer ที่คาดหวัง 20 ช่องว่างต่อ level สำหรับการ nesting ลึกๆ จะได้รับเพียง 10 ทำให้ format ใน generated file ไม่เป็นไปตามที่คาด
วิธีแก้: การเยื้องสูงสุดคือ 10 ช่องว่าง สำหรับโครงสร้างลึก ใช้การเยื้อง 2 ช่องว่าง (convention ที่พบบ่อยที่สุดในโปรเจกต์ JavaScript) และพึ่ง editor แบบ collapsible สำหรับการนำทาง
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 ไม่คุ้มค่า
คำถามที่พบบ่อย
จะพิมพ์ JSON ให้สวยใน JavaScript ได้อย่างไร?
เรียก JSON.stringify(data, null, 2) — อาร์กิวเมนต์ที่สามควบคุมการเยื้อง ส่ง 2 หรือ 4 สำหรับช่องว่าง หรือ "\t" สำหรับ tab ไม่ต้อง import หรือติดตั้ง: JSON คือ global object ในทุก JavaScript environment รวมถึงเบราว์เซอร์และ 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
// }พารามิเตอร์ `space` ใน JSON.stringify() ทำอะไร?
พารามิเตอร์ space ควบคุมการเยื้องใน output ส่งตัวเลข (1–10) สำหรับจำนวนช่องว่างต่อระดับ หรือ string เช่น "\t" เพื่อใช้ tab ค่าที่เกิน 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') // เยื้อง 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
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"
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 อย่างรวดเร็ว
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
// ใช้งานได้บน 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 ของ DevToolsJavaScript ให้การควบคุมอย่างสมบูรณ์ — replacer function, toJSON() แบบกำหนดเอง, การประมวลผลไฟล์ขนาดใหญ่ใน Node.js เมื่อต้องการเพียงตรวจสอบหรือแชร์ snippet ที่ format แล้ว JSON Formatter ของ ToolDeck คือทางที่เร็วที่สุด: วาง JSON แล้วรับผลลัพธ์ที่ format และ highlight แล้วโดยไม่ต้องตั้งค่า environment ใด ๆ
เครื่องมือที่เกี่ยวข้อง
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.