JSON داره بهت دروغ میگه
خلاصهٔ کاملتر
نویسنده تو این مقاله با یه مثال ساده شروع میکنه: یه شناسهی عددی بزرگ رو داخل آبجکت میذاره و سریالایزش میکنه، ولی رقم آخر خروجی فرق داره. نه خطایی پرتاب میشه، نه خروجی نامعتبره؛ فقط داده بیصدا عوض شده، و وقتی این عدد ته یه payload بزرگ باشه راحت از چشم میافته.
const payload = { id: 9007199254740993 }
console.log(JSON.stringify(payload))
// {"id":9007199254740992}به گفتهٔ نویسنده، خرابی حتی قبل از دخالت JSON رخ داده: جاوااسکریپت عددهای معمولی رو با فرمت IEEE 754 نگه میداره و فقط تا Number.MAX_SAFE_INTEGER دقیقه، در حالی که گرامر JSON چنین سقفی نداره. پس سرویسی با تایپ عددی بزرگتر میتونه سند کاملاً معتبری بفرسته که JSON.parse گردش کنه. BigInt هم چاره نیست، چون JSON تایپ متناظر نداره و سریالایز کردنش TypeError میده. پیشنهاد مقاله اینه که شناسههای بزرگ رو به شکل رشتهٔ decimal رد و بدل کنی و همین رو تو اسکیما صریح بنویسی.
دستهٔ دوم مشکلات سر undefinedه. جاوااسکریپت بین «پراپرتی اصلاً نیست» و «پراپرتی هست ولی مقدارش undefined» فرق میذاره، اما JSON این تمایز رو نداره و پراپرتی undefined کلاً حذف میشه. نتیجهش اینه که تو یه API آپدیت جزئی، آبجکتی که یعنی «دست نزن» و آبجکتی که یعنی «مقدارش نامعلومه» دقیقاً یه سند یکسان تولید میکنن:
const leaveUnchanged = {}
const ambiguousUpdate = { nickname: undefined }
console.log(JSON.stringify(leaveUnchanged)) // {}
console.log(JSON.stringify(ambiguousUpdate)) // {}تو آرایهها رفتار فرق داره: حذف عضو ایندکسهای بعدی رو جابهجا میکنه، برای همین undefined و تابع به null تبدیل میشن. نویسنده میگه قرارداد API باید فقط با همون دو حالتی تعریف بشه که JSON واقعاً حمل میکنه، یعنی نبودن فیلد و null.
دو تلهٔ آخر ترتیب کلیدها و پاک شدن تایپهاست. ترتیب پراپرتیها تو جاوااسکریپت پایداره، ولی RFC 8259 آبجکت رو مجموعهای بدون ترتیب تعریف کرده و مثلاً سرویس Go که همون سند رو تو map میریزه هیچ ترتیبی تضمین نمیکنه؛ اگه ترتیب معنا داره باید با آرایه مدلش کرد. تایپها هم رد نمیشن: Date به رشتهٔ ISO و NaN به null تبدیل میشه، بدون اینکه سند ردی از تایپ اصلی نگه داره.
نکات کلیدی:
- عددهای صحیح بزرگتر از Number.MAX_SAFE_INTEGER قبل از رسیدن به JSON گرد میشن؛ شناسهها رو رشته بفرست.
- BigInt سریالایز نمیشه و بهجاش TypeError میگیری.
- پراپرتی با مقدار undefined تو آبجکت حذف میشه ولی تو آرایه null میشه.
- ترتیب کلیدهای آبجکت جزو قرارداد JSON نیست؛ ترتیب معنادار رو با آرایه مدل کن.
- برای امضا، هش و کلید کش به یه نمایش canonical توافقشده نیاز داری.




