آموزش 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 | پایتون | جاوا اسکریپت |
|---|---|---|
| object | dict | Object |
| array | list | Array |
| string | str | String |
| number | int یا float | Number |
true / false | True / False | true / false |
null | None | null |
تبدیل داده به 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 value | Expecting ',' delimiter |
| مقدار پایتونی یا جاوا اسکریپتی | {"a": True} | Unexpected token 'T' | Expecting value |
| عدد با صفر ابتدایی | {"phone": 09121234567} | Unexpected number | Expecting ',' delimiter |
| رشته بستهنشده | {"a": "x} | Unterminated string | Unterminated string starting at |
| ورودی خالی | متن خالی | Unexpected end of JSON input | Expecting 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 حاوی توکن یا اطلاعات کاربران را هم با خیال راحت بررسی میکنید:
- JSON را در کادر JSON ورودی بچسبانید؛ همان لحظه قالببندی میشود و دکمه قالببندی هم همین کار را میکند.
- از منوی تورفتگی یکی از گزینههای ۲ فاصله، ۴ فاصله یا تب را انتخاب کنید.
- اگر JSON نامعتبر باشد، پیامی با
JSON نامعتبر است:و متن خطای مرورگر نمایش داده میشود که معمولاً موقعیت اشکال را هم دارد؛ با جدول بالا معنایش را پیدا و اصلاحش کنید. - زبانه درخت داده را به شکل درخت تاشو نشان میدهد و باز کردن همه و بستن همه همه شاخهها را باز یا بسته میکنند؛ برای پیدا کردن یک کلید در پاسخهای بزرگ بسیار کاربردی است.
- برای ارسال یا ذخیره فشرده، فشردهسازی همه فاصلهها و خطهای جدید را حذف میکند. نتیجه را با کپی بردارید.
وقتی کدتان برای JSON دریافتی به تایپ نیاز دارد، تبدیل JSON به تایپ از روی یک نمونه تعریفهای TypeScript، Go یا Python میسازد؛ راهنمای تایپ کردن پاسخ API در TypeScript این کار را قدمبهقدم توضیح میدهد.