آموزش JSON: ساختار، قواعد و کار با آن در جاوا اسکریپت و پایتون

JSON ساده‌ترین و رایج‌ترین قالب تبادل داده است؛ با چند قاعده کوتاه و دو تابع در هر زبان، می‌توانید هر داده‌ای را بخوانید، بسازید و ذخیره کنید.

همین حالا امتحان کنید: فرمت‌کننده JSON

اگر با API، اپلیکیشن موبایل یا حتی فایل تنظیمات یک پروژه سروکار دارید، دیر یا زود به JSON می‌رسید. JSON قالبی متنی برای نگهداری و جابه‌جایی داده است که هم انسان می‌خواندش و هم هر زبان برنامه‌نویسی به‌راحتی پردازشش می‌کند. در این آموزش از تعریف و قواعد نگارش شروع می‌کنیم، یک نمونه واقعی را بررسی می‌کنیم، بعد سراغ خواندن و نوشتن JSON در جاوا اسکریپت و پایتون می‌رویم، با توجه ویژه به متن فارسی، و در آخر خطاهای رایج و پیدا کردنشان با فرمت‌کننده JSON را می‌بینیم. همه کدهای این صفحه اجرا شده‌اند و خروجی‌ها واقعی‌اند.

JSON چیست؟

JSON مخفف JavaScript Object Notation است. نحوش از نوشتن شیء در جاوا اسکریپت گرفته شده، اما به هیچ زبانی وابسته نیست و پایتون، PHP، جاوا، سی‌شارپ، Go و تقریباً هر زبان دیگری ابزار آماده برای کار با آن دارد. قالب JSON در استانداردهای RFC 8259 و ECMA-404 تعریف شده، پسوند فایل‌هایش .json و نوع رسانه‌اش در وب application/json است. کاربردهای رایجش:

  • API‌های وب: بیشتر سرویس‌های امروزی درخواست و پاسخ را با JSON می‌فرستند.
  • فایل‌های تنظیمات: مثل package.json در پروژه‌های Node.js یا composer.json در PHP.
  • ذخیره داده: در localStorage مرورگر، ستون‌های JSON پایگاه داده‌هایی مثل PostgreSQL و MySQL و پایگاه داده‌های سندمحور.

قواعد نگارش JSON

هر سند JSON از شش نوع مقدار ساخته می‌شود که می‌توانند داخل هم قرار بگیرند:

نوعمثالتوضیح
شیء (object){"city": "شیراز"}جفت‌های کلید و مقدار داخل آکولاد
آرایه (array)[1, 2, 3]فهرست مرتب مقدارها داخل براکت
رشته (string)"سلام"متن داخل دابل‌کوتیشن
عدد (number)42، -3.5، 1.2e6صحیح یا اعشاری، بدون کوتیشن
بولی (boolean)true، falseفقط با حروف کوچک
تهی (null)nullنبودن مقدار

قاعده‌هایی که بیشترین خطا را می‌سازند:

  • کلیدها همیشه رشته‌اند و داخل دابل‌کوتیشن: {"name": "علی"} درست است و {name: "علی"} نادرست.
  • فقط دابل‌کوتیشن مجاز است؛ 'علی' با تک‌کوتیشن در JSON معتبر نیست.
  • کامای انتهایی ممنوع است: بعد از آخرین عضو شیء یا آرایه کاما نمی‌آید.
  • کامنت وجود ندارد: نه // و نه /* */.
  • مقدارهای خاص زبان‌ها ممنوع‌اند: undefined، NaN، Infinity، True و None در JSON معتبر نیستند.
  • عدد با صفر شروع نمی‌شود: 012 نامعتبر است. برای همین شماره موبایل، کد ملی و کد پستی را به شکل رشته بنویسید، مثل "09121234567"؛ صفر ابتدایی هم حفظ می‌شود.
  • نویسه‌های خاص داخل رشته Escape می‌شوند: \" برای دابل‌کوتیشن، \\ برای بک‌اسلش، \n برای خط جدید و \uXXXX برای هر نویسه یونیکد.
  • فاصله و خط جدید بین اجزا اهمیتی ندارد؛ برای همین JSON را هم می‌شود یک‌خطی و فشرده نوشت و هم مرتب و خوانا.

یک نمونه واقعی: سفارش یک فروشگاه اینترنتی

{
  "orderId": 10245,
  "createdAt": "2026-09-17T10:30:00Z",
  "customer": {
    "name": "مریم",
    "phone": "09121234567",
    "city": "اصفهان"
  },
  "items": [
    { "title": "کتاب آموزش پایتون", "price": 320000, "qty": 1 },
    { "title": "ماوس بی‌سیم", "price": 450000, "qty": 2 }
  ],
  "paid": true,
  "discountCode": null
}

در این نمونه همه انواع مقدار دیده می‌شوند. customer شیئی تودرتو است و items آرایه‌ای از شیءها. قیمت‌ها عددند، اما شماره تلفن رشته است تا صفر ابتدایی‌اش حفظ شود. JSON نوع «تاریخ» ندارد، پس زمان سفارش به شکل رشته و در قالب استاندارد ISO 8601 آمده است. discountCode هم با null می‌گوید این سفارش کد تخفیف نداشته است. برای خواندن قیمت کالای دوم، در جاوا اسکریپت می‌نویسید order.items[1].price و در پایتون order["items"][1]["price"].

کار با JSON در جاوا اسکریپت

جاوا اسکریپت دو تابع داخلی دارد که برای بیشتر کارها کافی‌اند: JSON.parse متن JSON را به شیء تبدیل می‌کند و JSON.stringify شیء را به متن JSON.

خواندن JSON با JSON.parse

const text = '{"name": "مریم", "age": 28, "skills": ["JavaScript", "Python"], "active": true}';
const user = JSON.parse(text);

console.log(user.name);       // مریم
console.log(user.skills[0]);  // JavaScript
console.log(user.active);     // true

ساخت JSON با JSON.stringify

const product = { title: "کتاب", price: 320000, tags: ["آموزشی", "پرفروش"], discount: null };

console.log(JSON.stringify(product));
console.log(JSON.stringify(product, null, 2));

فراخوانی اول JSON فشرده و یک‌خطی می‌دهد که برای ارسال روی شبکه مناسب است و دومی، با آرگومان سوم 2، خروجی خوانا با دو فاصله تورفتگی. آرگومان دوم برای فیلتر کردن یا تغییر مقدارهاست و معمولاً null می‌ماند. خروجی:

{"title":"کتاب","price":320000,"tags":["آموزشی","پرفروش"],"discount":null}
{
  "title": "کتاب",
  "price": 320000,
  "tags": [
    "آموزشی",
    "پرفروش"
  ],
  "discount": null
}

متن فارسی در خروجی JSON.stringify همان‌طور که هست می‌ماند و به کد \u تبدیل نمی‌شود.

دریافت JSON از API و ذخیره در localStorage

async function loadProduct() {
  const res = await fetch("https://api.example.com/products/1");
  return await res.json();
}

localStorage.setItem("cart", JSON.stringify({ items: [101, 205] }));
const cart = JSON.parse(localStorage.getItem("cart"));
console.log(cart.items.length); // 2

متد res.json() خودش پاسخ را parse می‌کند و شیء برمی‌گرداند؛ نتیجه‌اش را دوباره به JSON.parse ندهید. localStorage فقط رشته نگه می‌دارد، پس شیء را هنگام ذخیره با JSON.stringify و هنگام خواندن با JSON.parse تبدیل می‌کنیم.

مقدارهایی که JSON.stringify تغییر می‌دهد

const data = { a: undefined, b: () => 1, c: NaN, d: new Date(Date.UTC(2026, 8, 17)) };
console.log(JSON.stringify(data));
// {"c":null,"d":"2026-09-17T00:00:00.000Z"}

کلیدهایی با مقدار undefined یا تابع بی‌صدا حذف می‌شوند، NaN و Infinity به null تبدیل می‌شوند و تاریخ به رشته ISO. وقتی دوباره parse کنید، تاریخ رشته می‌ماند و خودکار به Date برنمی‌گردد.

مدیریت خطا

try {
  JSON.parse("{'name': 'Ali'}");
} catch (err) {
  console.log(err.name);    // SyntaxError
  console.log(err.message); // Expected property name or '}' in JSON at position 1 (line 1 column 2)
}

هر متن نامعتبر خطای SyntaxError می‌دهد، پس داده‌ای را که از بیرون می‌آید داخل try...catch پردازش کنید. پیام بالا خروجی Node.js است که با کروم یکی است؛ فایرفاکس و سافاری همین خطا را با عبارت دیگری نشان می‌دهند.

کار با JSON در پایتون

در پایتون ماژول استاندارد json همه کار را انجام می‌دهد و نصب چیزی لازم نیست. چهار تابع اصلی دارد: json.loads و json.dumps برای کار با رشته و json.load و json.dump برای کار مستقیم با فایل؛ حرف s در دو تابع اول از string می‌آید.

تبدیل رشته JSON به دیکشنری

import json

text = '{"name": "مریم", "age": 28, "skills": ["JavaScript", "Python"], "active": true}'
user = json.loads(text)

print(user["name"])     # مریم
print(type(user))       # <class 'dict'>
print(user["active"])   # True
JSONپایتونجاوا اسکریپت
objectdictObject
arraylistArray
stringstrString
numberint یا floatNumber
true / falseTrue / Falsetrue / false
nullNonenull

تبدیل داده به JSON و مشکل متن فارسی

product = {"title": "کتاب", "price": 320000, "tags": ["آموزشی", "پرفروش"], "discount": None}

print(json.dumps(product))
print(json.dumps(product, ensure_ascii=False, indent=2))

خط اول خروجی شاید غافلگیرتان کند:

{"title": "\u06a9\u062a\u0627\u0628", "price": 320000, "tags": ["\u0622\u0645\u0648\u0632\u0634\u06cc", "\u067e\u0631\u0641\u0631\u0648\u0634"], "discount": null}

json.dumps به‌طور پیش‌فرض هر نویسه غیر ASCII را به شکل \uXXXX می‌نویسد. این خروجی معتبر است و هر برنامه‌ای درست می‌خواندش، اما برای انسان ناخواناست و حجم بیشتری هم دارد. با ensure_ascii=False متن فارسی همان‌طور که هست نوشته می‌شود و indent=2 خروجی را دقیقاً مثل نمونه جاوا اسکریپت مرتب می‌کند.

خواندن و نوشتن فایل JSON

with open("product.json", "w", encoding="utf-8") as f:
    json.dump(product, f, ensure_ascii=False, indent=2)

with open("product.json", encoding="utf-8") as f:
    loaded = json.load(f)

print(loaded["tags"][0])   # آموزشی

دو نکته مهم: ensure_ascii=False را به json.dump هم بدهید و فایل را حتماً با encoding="utf-8" باز کنید. در ویندوز اگر encoding را مشخص نکنید، پایتون ممکن است از کدگذاری پیش‌فرض سیستم استفاده کند که UTF-8 نیست؛ نتیجه یا خطای UnicodeEncodeError است یا فایلی با حروف به‌هم‌ریخته.

خروجی print همان JSON نیست

print(product)
# {'title': 'کتاب', 'price': 320000, 'tags': ['آموزشی', 'پرفروش'], 'discount': None}

اشتباهی بسیار رایج این است که خروجی print یک دیکشنری را به‌عنوان JSON جایی بچسبانند. این متن نمایش پایتونی داده است: تک‌کوتیشن دارد و None به‌جای null، پس هیچ پارسر JSON قبولش نمی‌کند. برای ساخت JSON همیشه از json.dumps استفاده کنید.

مدیریت خطا در پایتون

try:
    json.loads("{'name': 'Ali'}")
except json.JSONDecodeError as e:
    print(e)  # Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

json.JSONDecodeError زیرکلاس ValueError است و ویژگی‌های lineno، colno و pos محل خطا را می‌دهند. اگر با کتابخانه requests کار می‌کنید، response.json() همین تبدیل را برای پاسخ API انجام می‌دهد. یک تفاوت ظریف: پایتون به‌طور پیش‌فرض NaN را هم در ورودی می‌پذیرد و هم در خروجی می‌نویسد، در حالی که این مقدار در JSON استاندارد نیست؛ برای جلوگیری، به json.dumps آرگومان allow_nan=False بدهید.

خطاهای رایج JSON و معنای پیام‌ها

اشتباهنمونه نادرستپیام جاوا اسکریپت (Node.js و کروم)پیام پایتون
تک‌کوتیشن یا کلید بدون کوتیشن{'name': 'Ali'}Expected property name or '}'Expecting property name enclosed in double quotes
کامای انتهایی در شیء{"a": 1,}Expected double-quoted property nameنسخه ۳٫۱۴: Illegal trailing comma before end of object؛ نسخه ۳٫۱۲: Expecting property name enclosed in double quotes
کامای انتهایی در آرایه[1, 2,]Unexpected token ']'نسخه ۳٫۱۴: Illegal trailing comma before end of array؛ نسخه ۳٫۱۲: Expecting value
کامای جاافتاده یا کامنت بعد از مقدار{"a": 1 "b": 2}Expected ',' or '}' after property valueExpecting ',' delimiter
مقدار پایتونی یا جاوا اسکریپتی{"a": True}Unexpected token 'T'Expecting value
عدد با صفر ابتدایی{"phone": 09121234567}Unexpected numberExpecting ',' delimiter
رشته بسته‌نشده{"a": "x}Unterminated stringUnterminated string starting at
ورودی خالیمتن خالیUnexpected end of JSON inputExpecting value

پیام‌ها معمولاً موقعیت را هم می‌گویند، مثل position 8 یا line 1 column 9، و اشکال واقعی اغلب درست قبل از همان نقطه است. اگر پیام جاوا اسکریپت با Unexpected token '<' شروع شود، احتمالاً به‌جای JSON یک صفحه HTML دریافت کرده‌اید؛ مثلاً صفحه خطای ۴۰۴ یا صفحه ورود. فایلی هم که با BOM ذخیره شده در پایتون خطای Unexpected UTF-8 BOM می‌دهد؛ آن را با encoding="utf-8-sig" باز کنید یا بدون BOM ذخیره کنید.

فرمت و اعتبارسنجی با فرمت‌کننده JSON

وقتی JSON طولانی در یک خط به دستتان می‌رسد یا نمی‌دانید چرا parse نمی‌شود، فرمت‌کننده JSON سریع‌ترین راه است. ابزار با پارسر JSON خود مرورگر کار می‌کند و داده از مرورگر شما بیرون نمی‌رود؛ پس پاسخ‌های API حاوی توکن یا اطلاعات کاربران را هم با خیال راحت بررسی می‌کنید:

  1. JSON را در کادر JSON ورودی بچسبانید؛ همان لحظه قالب‌بندی می‌شود و دکمه قالب‌بندی هم همین کار را می‌کند.
  2. از منوی تورفتگی یکی از گزینه‌های ۲ فاصله، ۴ فاصله یا تب را انتخاب کنید.
  3. اگر JSON نامعتبر باشد، پیامی با JSON نامعتبر است: و متن خطای مرورگر نمایش داده می‌شود که معمولاً موقعیت اشکال را هم دارد؛ با جدول بالا معنایش را پیدا و اصلاحش کنید.
  4. زبانه درخت داده را به شکل درخت تاشو نشان می‌دهد و باز کردن همه و بستن همه همه شاخه‌ها را باز یا بسته می‌کنند؛ برای پیدا کردن یک کلید در پاسخ‌های بزرگ بسیار کاربردی است.
  5. برای ارسال یا ذخیره فشرده، فشرده‌سازی همه فاصله‌ها و خط‌های جدید را حذف می‌کند. نتیجه را با کپی بردارید.

وقتی کدتان برای JSON دریافتی به تایپ نیاز دارد، تبدیل JSON به تایپ از روی یک نمونه تعریف‌های TypeScript، Go یا Python می‌سازد؛ راهنمای تایپ کردن پاسخ API در TypeScript این کار را قدم‌به‌قدم توضیح می‌دهد.

سوالات متداول

JSON چیست و چه فرقی با شیء جاوا اسکریپت دارد؟

JSON قالبی متنی برای نگهداری و تبادل داده است که نحوش از شیء جاوا اسکریپت گرفته شده، اما سخت‌گیرتر است: کلیدها باید داخل دابل‌کوتیشن باشند، کامنت و کامای انتهایی مجاز نیست و مقدارهایی مثل undefined و تابع در آن وجود ندارند.

چرا پایتون متن فارسی را در JSON به شکل \u0645 می‌نویسد؟

چون json.dumps به‌طور پیش‌فرض ensure_ascii=True دارد و نویسه‌های غیر ASCII را Escape می‌کند. خروجی معتبر است، اما برای خوانایی ensure_ascii=False را بدهید و فایل را با encoding="utf-8" بنویسید.

آیا می‌توان در فایل JSON کامنت نوشت؟

خیر. JSON استاندارد کامنت ندارد و JSON.parse و json.loads با دیدنش خطا می‌دهند. برخی ابزارها مثل تنظیمات VS Code قالب گسترش‌یافته‌ای با کامنت را می‌پذیرند، اما آن JSON استاندارد نیست.

فرق json.loads و json.load در پایتون چیست؟

json.loads رشته JSON را به داده پایتونی تبدیل می‌کند و json.load مستقیم از فایل باز می‌خواند. به همین ترتیب json.dumps رشته برمی‌گرداند و json.dump داده را در فایل می‌نویسد.
همین حالا امتحان کنید: فرمت‌کننده JSON