JSONمیتواند از نظرِ syntaxمعتبر باشد،اما گیرنده مقدارِ یک عددِ صحیحِ بزرگ را دقیق نگه ندارد. در این صفحه دو شناسهٔ عددیِ ساختگی را از متنِ خام باPythonوNodeواقعاًparseمیکنیم:درPythonمتفاوت میمانند،اما باNumberِJavaScriptبرابر میشوند. این خطایِ حفظِ مقدار است،نه خرابیِ دستوریِJSONیا کلیدِ تکراری.
از متنِ خام شروع کنیم،نه literalِ ازپیشگردشده
دو مقدار۹۰۰۷۱۹۹۲۵۴۷۴۰۹۹۲و۹۰۰۷۱۹۹۲۵۴۷۴۰۹۹۳را در یک رشتهٔJSONبا دو شیءِ idدار قرار دادهایم. درJavaScriptاین عددها را ابتدا بهصورتِNumberliteralنساختهایم؛همان متنِ اصلی بهJSON.parseمیرسد تا محلِ از دسترفتنِ دقت پنهان نشود. دادهها شناسهٔ مشتری،پرداخت یا پروندهٔ واقعی نیستند.
Python۳٫۱۲٫۱۴متن را به دوintِ متفاوت تبدیل و دوبارهserializeمیکند؛بازخوانی با همان مقدارها برابر است. اجرایِ واقعیِNodev22.13.1روی همین متن،دوnumberِ برابر با۹۰۰۷۱۹۹۲۵۴۷۴۰۹۹۲میدهد؛serializeِآن هم هر دوidرا با همان عدد مینویسد. نسخهها درJSONثبت شدهاند،نه از نامِ نرمافزار حدس زده شده باشند.
یک رقمِ متفاوت چطور از بین میرود؟
NumberِJavaScriptاز نمایشِ binary64استفاده میکند و همهٔ عددهای صحیحِ بزرگ را به فاصلهٔ یک واحد نگه نمیدارد. عددِ دومِ این جفت در آن تبدیل به همان مقدارِ قابلِ نمایشِ اول میشود. این مثال نمیگوید هر عددِ بزرگتر از۲بهتوان۵۳نامعتبر یا نمایشناپذیر است؛برخی عددهای بزرگتر هم دقیق نمایش داده میشوند،اما تضمینِ همهٔ عددهایِ متوالی را نداریم.
RFC8259بازهٔ صحیحِ منفیِ(۲بهتوان۵۳منهای۱)تا مثبتِ(۲بهتوان۵۳منهای۱)را برای توافقِ دقیقِ پیادهسازیهای متکی بهbinary64توضیح میدهد. این بازه را با سقفِ نحویِJSONیکی نکنیم. یک parserمیتواند دامنه و دقتِ متفاوتی داشته باشد؛قراردادِ دو طرف باید معلوم باشد.
| مسیرِ واقعیِ تمرین | آیا دوidمتفاوت ماندند؟ | نکته |
|---|---|---|
| متنِ خام→Pythonint | بله | رفتوبرگشتِ هر دو مقدار دقیق |
| همان متن→JavaScriptNumber | خیر | دو مقدار یکسان وserializeشده |
| همان رقمها بهصورتِ رشته | بله | قراردادِ نوع عوض شده است |
| BigIntازNumberِ قبلاًگردشده | اصل را برنمیگرداند | اطلاعات قبلاً از دست رفته است |
BigIntرا بعد از گمشدنِ اطلاعات نسازیم
کد واقعاًBigIntرا ازNumberِ دومِ parseشده میسازد؛نتیجه به رشته،۹۰۰۷۱۹۹۲۵۴۷۴۰۹۹۲است،نه مقدارِ اصلیِ پایانیافته به۳. بعد همان تبدیل را از رشتهٔ رقمهای اصلی انجام میدهد و۹۰۰۷۱۹۹۲۵۴۷۴۰۹۹۳دقیق بازمیگردد. تواناییِ نوعِ مقصد،اطلاعاتِ ازدسترفتهٔ ورودی را حدس نمیزند.
مستندِ MDNهم یادآوری میکندreviverپس ازparseاجرا میشود وNumberممکن است تا آن زمان دقت را از دست داده باشد. این تمرین به قابلیتِ جدیدِ context.sourceتکیه نکرده یا پشتیبانیِآن را آزمایششده اعلام نکرده است. راهِ نمونه،حفظِ متنِ اصلی و قراردادِ رشتهایِ صریح برای شناسه است.
شناسهٔ رشتهای یک تغییرِ قرارداد است
نسخهٔ دومِJSON،هر دوidرا از ابتدا داخلِ گیومه دارد. JavaScriptآنها راstringمیبیند،برابریشان نادرست است وserialize/parseِدوباره همان دو رشته را نگه میدارد. فرستنده و گیرنده باید این نوع را بپذیرند؛صرفِ عوضکردنِیک سمت ممکن است اعتبارسنجی یا lookupِمقصد را بشکند.
همهٔ قیمتها،اندازهها و محاسبات را به این دلیل رشته نکنید. شناسه معمولاً برای تشخیص است،اما کمیتِ حسابی قراردادِ محاسبهٔ خودش را لازم دارد. اگر تنها نسخهٔ گردشده باقی مانده،از روی آن idاصلی نسازید؛به منبعِ سالم برگردید و ردیفِ نامعلوم را جدا کنید. موفقیتِparse،شاهدِ صحتِ شناسه نیست.
با دو خطای نزدیک اشتباه نکنیم
کلیدِ تکراریِJSON حذفِ یک نام/مقدار هنگامِ ساختِ شیء را بررسی میکند؛اینجا دوشیءِ مستقل و دوNumberمتفاوتِ ورودی داریم. صفرِ آغازینِ شناسه درCSV هم تبدیلِ نوع در صفحهگسترده است؛این صفحه تصادمِ واقعیِ دوruntimeرا اجرا میکند.
PythonازNodeِ موجود استفاده میکند؛اگرنباشد خطا میدهد و نصبِ تازه انجام نمیدهد. هیچ شبکه،پرداخت یا دادهٔ خصوصی در کار نیست. برای بررسیِ اتصال در راهکارهای اپرا،نوع،دامنه و حفظِ دقیقِ شناسه را با تیمِ فنی مشخص کنید؛این مثال رفتارِ APIیاپایگاهِ داخلیِ محصول را اعلام نمیکند.
فایل تمرین و منبع
کدِ کاملِ محلی و کنترلهای اصیلِ تمرین · دادهٔ ساختگی و خروجیِ اجرای واقعی
- RFC8259،دسامبر۲۰۱۷،بخش۶؛دامنه و دقتِ عدد و سازگاریِbinary64؛فقط بخشِ مرتبط خوانده شد
- مرجعِMDNبرایJSON.parse؛هشدارِ افتِ دقت پیش ازreviverو حفظِ نوع؛قابلیتِcontext.sourceآزموده نشده است
منابع در 2026-11-04 خوانده شدند؛ این تاریخ، تاریخ انتشار منبع نیست. مثالها و فایلهای این راهنما آموزشی و ساختهٔ تحریریهاند.