JSON Formatter JavaScript — JSON.stringify()

·Front-end & Node.js Developer·مراجعة بواسطةMarcus Webb·نُشر

استخدم منسق ومُجمِّل JSON المجاني مباشرةً في متصفحك — لا حاجة للتثبيت.

جرّب منسق ومُجمِّل JSON أونلاين ←

حين أُصحح استجابات API في Node.js، يكون أول ما يُبطئني جداراً من JSON المضغوط — استدعاء واحد لـ JSON.stringify(data, null, 2) يجعل البنية مقروءة على الفور. لتنسيق JSON في JavaScript، لا تحتاج إلى أي شيء سوى بيئة التشغيل: JSON.stringify مدمج في كل متصفح وبيئة Node.js دون الحاجة إلى تثبيت. إذا كنت تحتاج فقط إلى نتيجة سريعة دون كتابة أي كود، فإن JSON Formatter من ToolDeck يقوم بذلك فوراً. يغطي هذا الدليل كل ما هو عملي: معامل space، مصفوفات ودوال replacer، التعامل مع Date و BigInt والمراجع الدائرية، قراءة وكتابة ملفات JSON في Node.js (18+)، الطباعة الجميلة من سطر الأوامر، ومكتبة fast-json-stringify للتسلسل في بيئة الإنتاج.

  • JSON.stringify(data, null, 2) مدمج في كل متصفح وNode.js — لا حاجة للتثبيت.
  • يقبل معامل replacer مصفوفة (قائمة بيضاء للمفاتيح) أو دالة (تحويل القيم) — استخدمه لإخفاء الحقول الحساسة.
  • تُسلسل كائنات Date تلقائياً عبر toJSON()‎ إلى سلسلة ISO 8601؛ أما BigInt فيرمي TypeError ويتطلب replacer مخصصاً.
  • المراجع الدائرية تُلقي TypeError — أصلحها بمجموعة seen في دالة replacer، أو استخدم مكتبة flatted.
  • للطباعة الجميلة من CLI استخدم node -p "JSON.stringify(require('./file.json'),null,2)" — لا تحتاج أدوات إضافية.

ما هو تنسيق JSON؟

تنسيق JSON (يُسمى أيضاً الطباعة الجميلة) يحوّل سلسلة JSON مضغوطة إلى تخطيط مقروء للإنسان مع مسافة بادئة متسقة وفواصل أسطر. البيانات الأساسية متطابقة — المسافة البيضاء فقط هي التي تتغير. JSON المضغوط مثالي لنقل الشبكة حيث تهم كل بايت؛ أما JSON المنسق فمثالي للتصحيح ومراجعة الكود وفحص السجلات. تتولى JSON.stringify() في JavaScript كلا الأمرين في استدعاء واحد عن طريق تبديل معامل space.

After · json
Before · json
{
  "orderId": "ord_8f2a91bc",
  "status": "shipped",
  "items": [
    {
      "sku": "HDMI-4K-2M",
      "qty": 2,
      "unitPrice": 12.99
    }
  ],
  "total": 25.98
}
{"orderId":"ord_8f2a91bc","status":"shipped","items":[{"sku":"HDMI-4K-2M","qty":2,"unitPrice":12.99}],"total":25.98}

JSON.stringify()‎ — المنسق المدمج

JSON.stringify() دالة عالمية في كل بيئة JavaScript — المتصفحات وNode.js وDeno وBun — دون الحاجة إلى استيراد. تتحكم وسيطتها الثالثة space في المسافة البادئة: مرر رقماً للحصول على ذلك العدد من المسافات لكل مستوى، أو السلسلة '\t' لعلامات التبويب. احذفها (أو مرر null) وستحصل على مخرجات مضغوطة في سطر واحد.

JavaScript — مثال عمل بسيط
const serverConfig = {
  host: "api.payments.internal",
  port: 8443,
  workers: 4,
  tls: { enabled: true, cert: "/etc/ssl/certs/api.pem" },
  rateLimit: { requestsPerMinute: 1000, burst: 50 }
}

console.log(JSON.stringify(serverConfig, null, 2))
// {
//   "host": "api.payments.internal",
//   "port": 8443,
//   "workers": 4,
//   "tls": {
//     "enabled": true,
//     "cert": "/etc/ssl/certs/api.pem"
//   },
//   "rateLimit": {
//     "requestsPerMinute": 1000,
//     "burst": 50
//   }
// }

يقبل معامل space إما رقماً (1–10 مسافات) أو سلسلة نصية. تمرير محرف علامة التبويب يُنتج مخرجات يفضلها كثير من المحررين وأدوات المقارنة. يمكنك أيضاً دمج المعاملات الثلاثة — إليك نمطاً واقعياً أستخدمه عند كتابة JSON منسق إلى ملفات الإعداد:

JavaScript — تنويعات space
const telemetryEvent = {
  eventId: "evt_3c7f9a2b",
  service: "checkout-api",
  severity: "warn",
  latencyMs: 342,
  region: "eu-west-1",
  tags: ["payment", "timeout", "retry"]
}

// مسافة بادئة من مسافتين (الأكثر شيوعاً في مشاريع JS)
JSON.stringify(telemetryEvent, null, 2)

// مسافة بادئة بعلامة التبويب (مفضل لدى بعض أدوات linter وإعداد)
JSON.stringify(telemetryEvent, null, '\t')

// مضغوط — بدون مسافات بيضاء (لنقل الشبكة)
JSON.stringify(telemetryEvent)
// {"eventId":"evt_3c7f9a2b","service":"checkout-api",...}
ملاحظة:قيم undefined والدوال و Symbol تُحذف بصمت من المخرجات. إذا كانت قيمة خاصية ما undefined، فلن يظهر ذلك المفتاح في السلسلة المُسلسلة على الإطلاق — وهذا مصدر شائع للأخطاء عند تسجيل كائنات تحتوي على حقول اختيارية.

دوال Replacer — تصفية المخرجات وتحويلها

الوسيطة الثانية لـ JSON.stringify() هي replacer. تأتي في شكلين: مصفوفة array تُدرج مفاتيح محددة في القائمة البيضاء، أو دالة تُستدعى لكل زوج مفتاح/قيمة ويمكنها تصفية القيم أو تحويلها أو إخفائها. أستخدم شكل المصفوفة حين أحتاج إلى مجموعة فرعية سريعة، وشكل الدالة حين أحتاج إلى إخفاء بيانات حساسة قبل التسجيل.

Replacer المصفوفة — إدراج مفاتيح محددة في القائمة البيضاء

JavaScript — replacer المصفوفة
const order = {
  orderId: "ord_8f2a91bc",
  customer: {
    id: "usr_4421",
    email: "m.alomari@example.sa",
    passwordHash: "bcrypt:$2b$12$XKzV..."
  },
  items: [{ sku: "HDMI-4K-2M", qty: 2, unitPrice: 12.99 }],
  createdAt: "2026-03-10T14:22:00Z"
}

// تضمين الحقول الآمنة فقط في مخرجات السجل
const safeLog = JSON.stringify(order, ["orderId", "items", "createdAt"], 2)
// {
//   "orderId": "ord_8f2a91bc",
//   "items": [{ "sku": "HDMI-4K-2M", "qty": 2, "unitPrice": 12.99 }],
//   "createdAt": "2026-03-10T14:22:00Z"
// }
// تم استبعاد passwordHash وcustomer.email

Replacer الدالة — تحويل القيم

JavaScript — replacer الدالة
const auditRecord = {
  requestId: "req_7d2e91",
  user: { id: "usr_4421", email: "m.alomari@example.sa", 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 "[محجوب]"
  if (key === "email") return value.replace(/(?<=.{2}).+(?=@)/, "***")
  return value
}

console.log(JSON.stringify(auditRecord, safeReplacer, 2))
// {
//   "requestId": "req_7d2e91",
//   "user": { "id": "usr_4421", "email": "m.***@example.sa", "apiKey": "[محجوب]" },
//   "action": "update_billing",
//   "timestamp": "2026-03-10T14:22:00.000Z",
//   "durationMs": 87
// }
ملاحظة:تُستدعى دالة replacer مع تعيين this على الكائن الذي يحتوي على المفتاح الحالي. الاستدعاء الأول يمرر سلسلة فارغة كمفتاح والقيمة الكاملة المراد تسلسلها كقيمة — أعدها دون تغيير للمتابعة مع التسلسل العادي.

التعامل مع الأنواع غير القابلة للتسلسل

لا تُعيَّن جميع قيم JavaScript بشكل نظيف إلى JSON. معرفة سلوك كل نوع يمنع الضياع الصامت للبيانات وأخطاء وقت التشغيل غير المتوقعة في كود الإنتاج.

Date — تلقائي عبر toJSON()‎

تُطبق كائنات Date طريقة toJSON() التي تُعيد سلسلة ISO 8601. تستدعي JSON.stringify() toJSON() تلقائياً قبل التسلسل، لذا لا يلزم أي معالجة مخصصة.

JavaScript — تسلسل Date
const webhook = {
  eventType: "payment.succeeded",
  occurredAt: new Date("2026-03-10T14:22:00Z"),
  processedAt: new Date()
}

JSON.stringify(webhook, null, 2)
// {
//   "eventType": "payment.succeeded",
//   "occurredAt": "2026-03-10T14:22:00.000Z",
//   "processedAt": "2026-03-10T14:22:01.347Z"
// }

// أي كائن لديه طريقة toJSON()‎ يحصل على نفس المعاملة:
const custom = { toJSON: () => "custom-value", hidden: 42 }
JSON.stringify(custom) // '"custom-value"'

الأصناف المخصصة — تطبيق toJSON()‎

يمكن لأي صنف تطبيق طريقة toJSON() وستستدعيها JSON.stringify() تلقائياً أثناء التسلسل. هذا أنظف من replacer عالمي لأنواع النطاق التي تظهر في جميع أنحاء قاعدة الكود.

JavaScript — toJSON()‎ مخصص
class Money {
  constructor(amount, currency) {
    this.amount = amount
    this.currency = currency
  }
  toJSON() {
    // تُستدعى تلقائياً بواسطة JSON.stringify
    return { amount: this.amount, currency: this.currency, formatted: `${this.currency} ${this.amount.toFixed(2)}` }
  }
}

class OrderId {
  constructor(id) { this.id = id }
  toJSON() { return this.id }  // تسلسل كسلسلة عادية
}

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

JSON.stringify(invoice, null, 2)
// {
//   "invoiceId": "inv_8f2a91bc",
//   "subtotal": { "amount": 199, "currency": "SAR", "formatted": "SAR 199.00" },
//   "tax": { "amount": 15.92, "currency": "SAR", "formatted": "SAR 15.92" },
//   "issuedAt": "2026-03-10T14:22:00.000Z"
// }
ملاحظة:toJSON() لها الأولوية على دالة replacer. إذا كان كلاهما موجوداً، تعمل toJSON() أولاً — يتلقى replacer القيمة المُحوَّلة بالفعل، وليس نسخة الصنف الأصلية.

BigInt — TypeError بدون Replacer

JavaScript — replacer BigInt
// هذا يُلقي: TypeError: Do not know how to serialize a BigInt
// JSON.stringify({ sessionId: 9007199254741234n })

// الحل: تحويل BigInt إلى سلسلة في 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"
// }

المراجع الدائرية — TypeError بدون مجموعة seen

JavaScript — replacer المرجع الدائري
// هذا يُلقي: TypeError: Converting circular structure to JSON
// const node = { id: "n1" }; node.self = node; JSON.stringify(node)

// الحل: تتبع الكائنات المرئية بـ WeakSet
function circularReplacer() {
  const seen = new WeakSet()
  return function (_key, value) {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) return '[دائري]'
      seen.add(value)
    }
    return value
  }
}

const parent = { id: "node_parent", label: "الجذر" }
const child  = { id: "node_child", parent }
parent.child = child  // دائري

JSON.stringify(parent, circularReplacer(), 2)
// {
//   "id": "node_parent",
//   "label": "الجذر",
//   "child": { "id": "node_child", "parent": "[دائري]" }
// }

// بديلاً: npm install flatted
// import { stringify } from 'flatted'
// stringify(parent)  // يتعامل مع المراجع الدائرية بشكل أصلي

مرجع معاملات JSON.stringify()‎

المعاملات الثلاثة مدعومة بالكامل في كل بيئة تشغيل JavaScript حديثة. تُنتج القيم الافتراضية JSON مضغوطاً في سطر واحد — مرر المعاملات صراحةً للحصول على مخرجات مقروءة.

المعامل
النوع
الافتراضي
الوصف
value
any
القيمة المراد تسلسلها. الكائنات والمصفوفات والسلاسل النصية والأرقام والقيم المنطقية وnull مدعومة بشكل أصلي.
replacer
function | Array<string | number> | null
null
تصفية أزواج المفتاح/القيمة أو تحويلها. المصفوفة = قائمة بيضاء من المفاتيح المراد تضمينها. الدالة = تُستدعى لكل مفتاح/قيمة.
space
number | string | null
null
المسافة البادئة. الرقم = مسافات لكل مستوى (بحد أقصى 10). السلسلة = مسافة بادئة حرفية (مثل "\t"). null أو 0 = مخرجات مضغوطة.

تنسيق JSON من ملف واستجابة API

في Node.js (18+) كثيراً ما تحتاج إلى إعادة تنسيق ملف إعداد JSON أو طباعة استجابة API بشكل جميل للتصحيح. يستخدم كلا النمطين نفس النهج ذي الخطوتين: تحليل النص الخام بـ JSON.parse()، ثم إعادة التسلسل بـ JSON.stringify().

قراءة ملف إعداد JSON وإعادة كتابته

Node.js 18+ — إعادة تنسيق ملف JSON (ESM)
import { readFileSync, writeFileSync } from 'fs'

try {
  const raw = readFileSync('./config/database.json', 'utf8')
  const config = JSON.parse(raw)
  writeFileSync('./config/database.json', JSON.stringify(config, null, 2))
  console.log('أُعيد تنسيق الإعداد بنجاح')
} catch (err) {
  console.error('فشل إعادة تنسيق الإعداد:', err.message)
  // يُلقي JSON.parse خطأ SyntaxError إذا كان الملف يحتوي على JSON غير صالح
  // يُلقي readFileSync خطأ ENOENT إذا لم يكن الملف موجوداً
}

إعادة تنسيق الملف بشكل غير متزامن (fs/promises)

Node.js 18+ — إعادة تنسيق الملف بشكل غير متزامن
import { readFile, writeFile } from 'fs/promises'

async function reformatJson(filePath) {
  const raw = await readFile(filePath, 'utf8')
  const parsed = JSON.parse(raw)
  const formatted = JSON.stringify(parsed, null, 2)
  await writeFile(filePath, formatted, 'utf8')
  return { keys: Object.keys(parsed).length }
}

// الاستخدام
const { keys } = await reformatJson('./config/feature-flags.json')
console.log(`أُعيد تنسيق ${keys} مفتاحاً على المستوى الأعلى`)

الطباعة الجميلة لـ JSON من استجابة fetch()‎

عند بناء عميل API أو تصحيحه في Node.js 18+ أو المتصفح، الطباعة الجميلة لجسم الاستجابة هي أسرع طريقة لفهم ما أعاده الخادم. النمط القياسي هو response.json() (كائن مُحلَّل) ثم JSON.stringify(). إذا كنت تحتاج إلى السلسلة الخام أولاً — مثلاً لحساب تجزئة أو تسجيلها كما هي — استخدم response.text() ثم JSON.parse().

JavaScript — fetch + طباعة جميلة (Node.js 18+ أو المتصفح)
// النمط 1: response.json()‎ → طباعة جميلة
async function debugEndpoint(url) {
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
  })
  if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`)

  const data = await res.json()
  console.log(JSON.stringify(data, null, 2))
}

await debugEndpoint('https://api.stripe.com/v1/charges?limit=3')
JavaScript — response.text()‎ عندما تحتاج السلسلة الخام أولاً
// النمط 2: 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 وخطوط نشر التطبيقات والاختصارات في الصدفة. للاستخدام التفاعلي الأسرع، ثبّت jq — المعيار الفعلي للتعامل مع JSON في سطر الأوامر.

bash — طباعة جميلة لملف JSON مع Node.js
# طباعة package.json جميلاً باستخدام node -p (print)
node -p "JSON.stringify(require('./package.json'), null, 2)"

# طباعة جميلة من stdin (متوافق مع الأنابيب، يعمل في CI)
echo '{"port":3000,"env":"production"}' | node -e "
  const d = require('fs').readFileSync(0, 'utf8')
  console.log(JSON.stringify(JSON.parse(d), null, 2))
"

# طباعة جميلة لاستجابة API محفوظة في ملف
cat api-response.json | node -e "
  process.stdin.setEncoding('utf8')
  let s = ''
  process.stdin.on('data', c => s += c)
  process.stdin.on('end', () => console.log(JSON.stringify(JSON.parse(s), null, 2)))
"
bash — بدائل عالمية
# Python كبديل (مثبت مسبقاً على macOS ومعظم توزيعات Linux)
cat api-response.json | python3 -m json.tool

# jq — الأسرع والأكثر ميزات (brew install jq / apt install jq)
cat api-response.json | jq .

# jq — طباعة جميلة وتصفية في خطوة واحدة
cat api-response.json | jq '.data.users[] | {id, email}'
ملاحظة:عند تشغيل Node.js في وضع ESM (مثل "type": "module" في package.json)، require() غير متاح في الأوامر المختصرة. استخدم --input-type=module و fs.readFileSync بدلاً من ذلك، أو انتقل إلى node -e مع مقتطف CommonJS كما هو موضح أعلاه.

إذا لم تكن على الطرفية أصلاً — لصق استجابة من Postman أو ملف سجل — فإن JSON Formatter من ToolDeck يتيح لك اللصق والتنسيق والنسخ في خطوة واحدة، مع تمييز الصيغة والتحقق المدمجين.

بديل عالي الأداء — fast-json-stringify

تُولّد fast-json-stringify دالة تسلسل مخصصة من JSON Schema. لأنها تعرف شكل البيانات مسبقاً، يمكنها تخطي التحقق من النوع واستخدام تسلسل السلاسل بدلاً من الهبوط التعاودي — تُظهر المعايير عادةً تحسناً في الإنتاجية بمقدار 2–5 أضعاف على JSON.stringify() للحمولات الكبيرة والمتكررة. أستخدمه في مسارات API عالية التردد حيث تظهر تكلفة التسلسل في آثار المحلل.

bash
npm install fast-json-stringify
JavaScript — fast-json-stringify لأحداث القياس عن بُعد
import fastJson from 'fast-json-stringify'

const serializeTelemetryEvent = fastJson({
  title: 'TelemetryEvent',
  type: 'object',
  properties: {
    eventId:   { type: 'string' },
    service:   { type: 'string' },
    severity:  { type: 'string', enum: ['info', 'warn', 'error'] },
    latencyMs: { type: 'integer' },
    timestamp: { type: 'string' },
    region:    { type: 'string' }
  },
  required: ['eventId', 'service', 'severity', 'latencyMs', 'timestamp']
})

const event = {
  eventId:   'evt_3c7f9a2b',
  service:   'checkout-api',
  severity:  'warn',
  latencyMs: 342,
  timestamp: new Date().toISOString(),
  region:    'eu-west-1'
}

const json = serializeTelemetryEvent(event)
// '{"eventId":"evt_3c7f9a2b","service":"checkout-api","severity":"warn",...}'
ملاحظة:fast-json-stringify مصممة للتسلسل في إنتاج البيانات المنظمة — تُنتج دائماً مخرجات مضغوطة (بدون طباعة جميلة). للمخرجات المقروءة للإنسان أثناء التطوير، استخدم JSON.stringify(data, null, 2) كالمعتاد.

مخرجات الطرفية مع تمييز الصياغة

تُنتج util.inspect() المدمجة في Node.js مخرجات ملونة مقروءة للإنسان مُحسَّنة لعرض الطرفية. تتعامل مع المراجع الدائرية وBigInt بشكل أصلي، وتُصيّر الكائنات المتداخلة بشكل تعاودي إلى أي عمق. المخرجات ليست JSON صالحاً — تستخدم صياغة JavaScript (مثلاً تُصيّر الدوال والرموز بدلاً من حذفها)، مما يجعلها مثالية لسكريبتات تصحيح Node.js ولكنها غير مناسبة لاستجابات API أو مخرجات الملفات.

Node.js 18+ — util.inspect مع الألوان
import { inspect } from 'util'

const payload = {
  requestId: "req_7d2e91",
  user: { id: "usr_4421", roles: ["admin", "billing"] },
  metadata: { ipAddress: "203.0.113.42", userAgent: "Mozilla/5.0" },
  createdAt: new Date()
}

// depth: null → توسيع جميع المستويات المتداخلة; colors: true → ألوان طرفية ANSI
console.log(inspect(payload, { colors: true, depth: null }))
تحذير:لا تستخدم util.inspect() للـ JSON المكتوب في الملفات أو المُرسل عبر الشبكة أو المخزن في قاعدة بيانات. مخرجاته ليست JSON صالحاً وستتسبب في أخطاء تحليل في أي نظام ينزل يستدعي JSON.parse() عليها. احتفظ بها لتصحيح الطرفية التفاعلي فقط.

التعامل مع ملفات JSON الكبيرة

تُحمّل JSON.parse() الملف بالكامل في الذاكرة قبل التحليل — مناسب للحمولات الصغيرة، لكنه غير عملي للملفات التي تتجاوز 50–100 ميجابايت مثل تصديرات قواعد البيانات وتفريغ سجلات التطبيقات أو دفعات التحليلات. في هذه الحالات، يتيح لك Streams في Node.js ومكتبة stream-json معالجة السجلات واحداً تلو الآخر دون استنزاف الكومة.

التحليل التدفقي مع stream-json

bash
npm install stream-json
Node.js 18+ — stream-json للمصفوفات الكبيرة
import { pipeline } from 'stream/promises'
import { createReadStream } from 'fs'
import { parser } from 'stream-json'
import { streamArray } from 'stream-json/streamers/StreamArray.js'

// events.json = مصفوفة من ملايين الكائنات — لا تُحمَّل بالكامل في الذاكرة أبداً
await pipeline(
  createReadStream('./events.json'),
  parser(),
  streamArray(),
  async function* (source) {
    for await (const { value: event } of source) {
      if (event.severity === 'error') {
        console.log(JSON.stringify(event, null, 2))
      }
    }
  }
)

NDJSON / JSON Lines — بدون تبعيات إضافية

يخزن NDJSON (JSON محدود بسطر جديد) كائن JSON واحداً لكل سطر وهو شائع في تصديرات Kafka ومخرجات BigQuery وخطوط أنابيب السجلات المنظمة. يتعامل معه readline المدمج في Node.js دون أي حزم خارجية.

Node.js 18+ — NDJSON مع 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() إلى التدفق عندما يتجاوز ملف JSON لديك 50–100 ميجابايت أو عند معالجة تدفق غير محدود (Kafka، خط أنابيب السجلات). لـ NDJSON / JSON Lines استخدم readline — لا يتطلب تبعيات إضافية.

الأخطاء الشائعة

تظهر هذه الأخطاء الأربعة بشكل متكرر في مراجعات الكود وتقارير أخطاء الإنتاج. كل منها ينطوي على سلوك دقيق لـ JSON.stringify() يسهل إغفاله ويصعب تصحيحه لاحقاً.

نسيان أن قيم undefined تُحذف بصمت

المشكلة: خصائص الكائن ذات القيم undefined تُحذف كلياً من مخرجات JSON — لا يوجد تحذير أو خطأ. يتسبب هذا في ضياع بيانات غير مرئي عندما تحتوي الكائنات على حقول اختيارية.

الحل: استخدم null للقيم الغائبة عمداً التي يجب أن تظهر في المخرجات المُسلسلة. احتفظ بـ undefined فقط للحقول التي يجب استبعادها من JSON.

After · JavaScript
Before · JavaScript
const userProfile = {
  userId: "usr_4421",
  displayName: "محمد العمري",
  avatarUrl: null,   // غائبة عمداً — تظهر في المخرجات
  bio: null          // غائبة عمداً — تظهر في المخرجات
}

JSON.stringify(userProfile, null, 2)
// {
//   "userId": "usr_4421",
//   "displayName": "محمد العمري",
//   "avatarUrl": null,
//   "bio": null
// }
const userProfile = {
  userId: "usr_4421",
  displayName: "محمد العمري",
  avatarUrl: undefined,   // ستختفي بصمت
  bio: undefined          // ستختفي بصمت
}

JSON.stringify(userProfile, null, 2)
// { "userId": "usr_4421", "displayName": "محمد العمري" }
// avatarUrl وbio اختفتا — لا تحذير
BigInt يُلقي TypeError

المشكلة: تمرير قيمة BigInt إلى JSON.stringify()‎ يُلقي TypeError في وقت التشغيل. هذا تعطل صارم، وليس حذفاً صامتاً — سيظهر في الإنتاج إذا تجاوز أي حقل رقمي Number.MAX_SAFE_INTEGER.

الحل: استخدم دالة replacer تحوّل قيم BigInt إلى سلاسل قبل التسلسل. بديلاً، حوّل BigInt إلى سلسلة أو Number في طبقة البيانات قبل تمريره إلى JSON.stringify.

After · JavaScript
Before · JavaScript
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"
// }
const session = {
  sessionId: 9007199254741234n,  // حرفي BigInt
  userId: "usr_4421",
  startedAt: "2026-03-10T14:00:00Z"
}

JSON.stringify(session, null, 2)
// Uncaught TypeError: Do not know how to serialize a BigInt
تعطل المراجع الدائرية

المشكلة: الكائنات التي تُشير إلى نفسها — الشائعة في أشجار DOM والقوائم المرتبطة وبعض مجموعات نتائج ORM — تُلقي TypeError عند تمريرها إلى JSON.stringify(). يحدث الخطأ فقط وقت التسلسل، في الغالب بعيداً من المكان الذي نشأ فيه المرجع الدائري.

الحل: استخدم دالة replacer مع WeakSet للكشف عن المراجع الدائرية واستبدالها، أو ثبّت مكتبة flatted كبديل جاهز يتعامل مع البنى الدائرية بشكل أصلي.

After · JavaScript
Before · JavaScript
import { stringify } from 'flatted'  // npm install flatted

const dept = { id: "dept_eng", name: "الهندسة" }
const team = { id: "team_frontend", dept }
dept.teams = [team]

// flatted تتعامل مع المراجع الدائرية — ملاحظة: المخرجات بتنسيق flatted وليس JSON قياسي
stringify(dept)

// أو استخدم replacer مبني على WeakSet إذا كنت تحتاج مخرجات JSON قياسية:
function circularReplacer() {
  const seen = new WeakSet()
  return (_key, value) => {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) return '[دائري]'
      seen.add(value)
    }
    return value
  }
}
JSON.stringify(dept, circularReplacer(), 2)
const dept = { id: "dept_eng", name: "الهندسة" }
const team = { id: "team_frontend", dept }
dept.teams = [team]  // دائري: dept → team → dept

JSON.stringify(dept, null, 2)
// Uncaught TypeError: Converting circular structure to JSON
استخدام space > 10 (يُقتطع بصمت)

المشكلة: تمرير قيمة space أكبر من 10 إلى JSON.stringify()‎ لا يُلقي خطأ — تُقتطع القيمة بصمت إلى 10. المطورون الذين يتوقعون 20 مسافة للمسافة البادئة للتداخل العميق سيحصلون على 10 فقط، مما يؤدي إلى تنسيق غير متوقع في الملفات المُولَّدة.

الحل: الحد الأقصى للمسافة البادئة هو 10 مسافات. للبنى العميقة، فضّل مسافة بادئة من مسافتين (الاتفاق الأكثر شيوعاً في مشاريع JavaScript) واعتمد على المحررات القابلة للطي للتنقل.

After · JavaScript
Before · JavaScript
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"
//       }
//     }
//   }
// }
const deepConfig = { server: { tls: { certs: { primary: "/etc/ssl/api.pem" } } } }

// نتوقع مسافة بادئة من 20 — لكن space مقتطعة إلى 10
JSON.stringify(deepConfig, null, 20)
// نفس مخرجات JSON.stringify(deepConfig, null, 10)
// لا خطأ، لا تحذير — اقتُطعت بصمت

JSON.stringify مقارنةً بالبدائل — مقارنة سريعة

تستدعي حالات مختلفة أدوات مختلفة. JSON.stringify مع replacer يغطي معظم حالات الاستخدام في الإنتاج بدون أي تبعيات. util.inspect هو الخيار الصحيح للتصحيح السريع في الطرفية عندما تحتاج إلى مخرجات ملونة ولا تحتاج إلى JSON صالح. fast-json-stringify يستحق العناء في المسارات عالية الإنتاجية حيث يُظهر التحليل تكلفة التسلسل؛ في كل شيء آخر لا تستحق أعباء صيانة المخطط ذلك.

الطريقة
مخرجات جميلة
JSON صالح
Non-ASCII
أنواع مخصصة
المراجع الدائرية
يتطلب تثبيتاً
JSON.stringify
⚠️ عبر replacer
✗ (يرمي خطأ)
لا
JSON.stringify + replacer
✅ تحكم كامل
لا
util.inspect
✅ أصلي
لا (مدمج في Node)
fast-json-stringify
❌ Schema فقط
npm install
flatted
✗ (تنسيق مخصص)
✅ دائري فقط
npm install
jq (CLI)
غير متاح
غير متاح
تثبيت النظام

الأسئلة الشائعة

كيف أطبع JSON بشكل منسق في JavaScript؟

استدعِ JSON.stringify(data, null, 2) — المعامل الثالث يتحكم في المسافة البادئة. مرر 2 أو 4 للمسافات، أو "\t" لعلامات التبويب. لا حاجة لاستيراد أو تثبيت: JSON كائن عالمي في كل بيئة JavaScript، بما في ذلك المتصفحات وNode.js.

JavaScript
const config = { host: "api.payments.internal", port: 8443, tls: true }
console.log(JSON.stringify(config, null, 2))
// {
//   "host": "api.payments.internal",
//   "port": 8443,
//   "tls": true
// }

ما الذي يفعله معامل `space` في JSON.stringify()؟

يتحكم معامل space في المسافة البادئة في المخرجات. مرر رقماً (1–10) لعدد المسافات المحدد لكل مستوى، أو سلسلة نصية مثل "\t" لاستخدام محرف علامة التبويب. القيم التي تتجاوز 10 تُقتطع بصمت إلى 10. تمرير null أو 0 أو حذف المعامل يُنتج JSON مضغوطاً في سطر واحد.

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

JSON.stringify(data, null, 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 أو دوال أو Symbols — هذه الأنواع ليس لها تمثيل في JSON. إذا كانت القيمة ذاتها على المستوى الأعلى undefined، تُعيد الدالة undefined (وليس السلسلة "undefined"). استخدم null بدلاً من undefined للحقول الاختيارية التي يجب أن تظهر في المخرجات.

JavaScript
const event = {
  traceId: "tr_9a2f",
  handler: () => {},        // دالة — محذوفة
  requestId: undefined,     // undefined — محذوفة
  sessionId: Symbol("s"),   // Symbol — محذوفة
  status: "ok"
}
JSON.stringify(event, null, 2)
// { "traceId": "tr_9a2f", "status": "ok" }

كيف أتعامل مع كائنات Date عند تنسيق JSON؟

تمتلك كائنات Date طريقة toJSON()‎ مدمجة تُعيد سلسلة ISO 8601، لذا يتعامل معها JSON.stringify تلقائياً. لا تحتاج إلى replacer مخصص للتواريخ — ستكون القيمة المُسلسلة سلسلة مثل "2026-03-10T14:22:00.000Z".

JavaScript
const order = {
  orderId: "ord_8f2a91bc",
  placedAt: new Date("2026-03-10T14:22:00Z"),
  total: 42.98
}
JSON.stringify(order, null, 2)
// {
//   "orderId": "ord_8f2a91bc",
//   "placedAt": "2026-03-10T14:22:00.000Z",
//   "total": 42.98
// }

كيف أنسق سلسلة JSON نصية (وليس كائناً) في JavaScript؟

حلل السلسلة أولاً باستخدام JSON.parse()‎، ثم أعد تسلسلها باستخدام JSON.stringify()‎. يمكن ربط الاستدعائين في سطر واحد للتصحيح السريع.

JavaScript
const raw = '{"endpoint":"/api/v2/users","timeout":30,"retry":true}'
const formatted = JSON.stringify(JSON.parse(raw), null, 2)
console.log(formatted)
// {
//   "endpoint": "/api/v2/users",
//   "timeout": 30,
//   "retry": true
// }

هل يمكن استخدام JSON.stringify()‎ في المتصفح؟

نعم. JSON كائن عالمي مدمج في كل متصفح حديث منذ IE8 — لا حاجة لعلامات script أو استيراد. افتح وحدة تحكم أدوات المطور واستدعِ JSON.stringify()‎ مباشرة. يعمل بشكل مطابق لإصدار Node.js، بنفس توقيع المعاملات ونفس القيود حول BigInt والمراجع الدائرية.

JavaScript
// يعمل في Chrome وFirefox وSafari وEdge — لا حاجة لاستيراد
const payload = { userId: "usr_7b3c", action: "checkout", cart: ["SKU-001", "SKU-002"] }
copy(JSON.stringify(payload, null, 2)) // copy()‎ مساعد أدوات المطور

يمنحك JavaScript تحكماً كاملاً — دوال replacer، toJSON() مخصص، معالجة الملفات الكبيرة في Node.js. عندما تحتاج فقط إلى فحص أو مشاركة مقتطف منسق، JSON Formatter من ToolDeck هو الطريق الأسرع: الصق JSON واحصل على نتيجة منسقة ومميزة دون أي إعداد بيئة.

الأدوات ذات الصلة

متاح أيضاً بـ:PythonGoBash
AC
Alex ChenFront-end & Node.js Developer

Alex is a front-end and Node.js developer with extensive experience building web applications and developer tooling. He is passionate about web standards, browser APIs, and the JavaScript ecosystem. In his spare time he contributes to open-source projects and writes about modern JavaScript patterns, performance optimisation, and everything related to the web platform.

MW
Marcus Webbالمراجع التقني

Marcus specialises in JavaScript performance, build tooling, and the inner workings of the V8 engine. He has spent years profiling and optimising React applications, working on bundler configurations, and squeezing every millisecond out of critical rendering paths. He writes about Core Web Vitals, JavaScript memory management, and the tools developers reach for when performance really matters.