منذ وقت ليس ببعيد ،
تباهى JavaScript بنوع بيانات
BigInt بدائي جديد للعمل بأرقام دقة عشوائية. الحد الأدنى الضروري من المعلومات قد تم
إخباره /
ترجمته بالفعل حول حالات الدوافع والاستخدام. وأود أن أولي اهتمامًا أكبر بـ "explicitness" المحلي الذي تم تجاوزه في تحويل النوع و
TypeError غير المتوقع. هل سنبخ أو نفهم ونغفر (مرة أخرى)؟
ضمني يصبح صريحا؟
في اللغة التي اعتاد على تحويل النوع الضمني إليها منذ فترة طويلة ، أصبح هذا الأمر بمثابة أي مؤتمر تقريبًا وفاجأ عدد قليل من الأشخاص بمثل هذه التعقيدات مثل:
1 + {};
لقد حصلنا فجأة على TypeError ، في محاولة لإضافة رقمين على ما يبدو:
1 + 1n;
وإذا لم تؤد التجربة السابقة للشهود إلى انهيار في تعلم اللغة ، فهناك فرصة ثانية لتحطيم وطرح كتاب ECMA والدخول في بعض برامج Java.
علاوة على ذلك ، تستمر اللغة في "التصيد" للمطورين js:
1n + '1';
أوه نعم ، لا تنسى عامل التشغيل الأحادي
+ :
+1n;
باختصار ، لا يمكننا خلط
BigInt و
Number في العمليات. نتيجة لذلك ، لا يوصى باستخدام "أعداد صحيحة كبيرة" إذا كان 2 ^ 53-1 (
MAX_SAFE_INTEGER ) كافياً لأغراضنا.
القرار الرئيسي
نعم ، كان هذا هو القرار الرئيسي لهذا الابتكار. إذا نسيت أن هذا هو JavaScript ، فكل شيء منطقي جدًا: تساهم هذه التحويلات الضمنية في فقدان المعلومات.
عندما نضيف قيمتين لأنواع رقمية مختلفة (أعداد صحيحة كبيرة وأرقام الفاصلة العائمة) ، قد تكون القيمة الرياضية للنتيجة خارج نطاق القيم الممكنة. على سبيل المثال ، لا يمكن تمثيل قيمة التعبير
(2n ** 53n + 1n) + 0.5 بدقة بواسطة أي من هذه الأنواع. لم يعد هذا عددًا صحيحًا ، ولكنه رقم حقيقي ، لكن دقته لم تعد مضمونة
بتنسيق float64 :
2n ** 53n + 1n;
في معظم اللغات الديناميكية ، حيث يتم تقديم أنواع لكل من الأعداد الصحيحة والعوامات ، تتم كتابة الأولى على شكل
1 ، والثانية في
1.0 . وبالتالي ، خلال العمليات الحسابية على وجود فاصل عشري في المعامل ، يمكننا أن نستنتج أن دقة التعويم في العمليات الحسابية مقبولة. لكن جافا سكريبت ليست واحدة منهم ، و
1 تعويم! وهذا يعني أن الحوسبة
2n ** 53n + 1 ستعيد تعويم 2 ^ 53. والتي بدورها تقطع الوظائف الرئيسية لـ
BigInt :
2 ** 53 === 2 ** 53 + 1;
حسنًا ، ليس هناك سبب للحديث عن تطبيق
"البرج العددي" أيضًا ، حيث أنك لن تكون قادرًا على أخذ الرقم الموجود كنوع بيانات رقمي عام (لنفس السبب).
ولتجنب هذه المشكلة ، تم حظر المصبوب الضمني بين
Number و
BigInt في العمليات. نتيجةً لذلك ، لا يمكن إدخال "عدد صحيح كبير" بأمان في أي من وظائف JavaScript أو Web API ، حيث يتوقع الرقم المعتاد:
Math.max(1n, 10n);
يجب عليك تحديد أحد هذين النوعين بشكل صريح باستخدام
Number () أو
BigInt () .
بالإضافة إلى ذلك ، بالنسبة للعمليات ذات الأنواع المختلطة ، هناك
تفسير حول التنفيذ المعقد أو فقدان الأداء ، وهو أمر شائع جدًا للتوافق مع ابتكارات اللغة.
بالطبع ، هذا ينطبق على التحويلات العددية الضمنية مع البدائل الأخرى:
1 + true;
ولكن ستعمل السلاسل التالية (بالفعل) ، حيث أن النتيجة المتوقعة عبارة عن سلسلة:
1n + [0];
استثناء آخر في شكل عوامل المقارنة (مثل
< و
> و
== ) بين
Number و
BigInt . لا يوجد أيضًا فقدان للدقة ، حيث إن النتيجة منطقية.
حسنًا ، إذا كنت تتذكر نوع بيانات
Symbol الجديد السابق ، فهل لم تعد TypeError تبدو مثل هذه الإضافة الجذرية؟
Symbol() + 1;
ونعم ، ولكن لا. في الواقع ، ليس رمز المفهوم رقماً على الإطلاق ، بل برمته - كثيرًا:
- من غير المرجح أن يقع هذا الرمز في مثل هذا الموقف. ومع ذلك ، هذا أمر مشبوه للغاية و TypeError مناسب تمامًا هنا.
- من المحتمل جدًا والمعتاد أن يصبح "الكل الكبير" في العمليات واحدًا من المعاملات عندما لا يكون هناك أي خطأ.
يطرح عامل التشغيل unary
+ استثناء بسبب مشكلة التوافق مع
asm.js ، حيث يتوقع
Number . لا يمكن أن تعمل علامة unary plus مع
BigInt بنفس طريقة
الرقم ، لأنه في هذه الحالة ، ستصبح شفرة asm.js السابقة غامضة.
عرض بديل
على الرغم من البساطة النسبية و "النظافة" لتطبيق
BigInt ، تؤكد
أكسل راوشماير على نقص الابتكار. وهي توافقه الخلفي الجزئي الوحيد مع
العدد الحالي وما يليه:
استخدم الأرقام لما يصل إلى 53 بت. استخدم الأعداد الصحيحة إذا كنت بحاجة إلى مزيد من البتات
كبديل ،
اقترح ما يلي .
اسمح ليصبح
Number نموذجًا فائقًا لـ
Int و
Double الجديد:
- اكتب 123.0 === 'number' ، و Number.isDouble (123.0) === true
- typeof 123 === 'number' و Number.isInt (123) === true
مع وظائف جديدة
لتحويلات Number.asInt () و
Number.asDouble () . وبطبيعة الحال ، مع التحميل الزائد للمشغل ويلقي اللازمة:
- Int × مزدوج = مزدوج (مسبوكة)
- مزدوج × كثافة العمليات = مزدوج (مع الزهر)
- مزدوج × مزدوج = مزدوج
- Int × Int = Int (جميع المشغلين باستثناء القسمة)
ومن المثير للاهتمام ، في النسخة المبسطة ، تدير هذه الجملة (في البداية) دون إضافة أنواع جديدة إلى اللغة. بدلاً من ذلك ،
يتم توسيع
تعريف "نوع الرقم" : بالإضافة إلى جميع الأرقام المزدوجة الممكنة 64 بت (IEEE 754-2008) ، يشمل الرقم الآن جميع الأعداد الصحيحة.
ونتيجة لذلك ، فإن "الرقم غير الدقيق"
123.0 و "الرقم الدقيق"
123 هما
رقمان منفصلان من نوع
الرقم الفردي.
يبدو مألوفا جدا ومعقولة. ومع ذلك ، هذه ترقية خطيرة للعدد الحالي ، والذي من المرجح أن يؤدي إلى "كسر الويب" وأدواته:
- هناك فرق بين 1 و 1.0 ، وهو ما لم يكن هناك من قبل. يستخدمهم الكود الموجود بشكل متبادل ، والذي بعد الترقية يمكن أن يؤدي إلى الارتباك (على عكس اللغات التي كان هذا الاختلاف موجودًا في البداية).
- هناك تأثير عندما يكون 1 === 1.0 (من المفترض أن يكون ترقية) ، وفي الوقت نفسه ، Number.isDouble (1)! == Number.isDouble (1.0) : مرة أخرى ، يكون الأمر كذلك.
- تختفي "خصوصية" المساواة 2 ^ 53 و 2 ^ 53 + 1 ، مما يؤدي إلى كسر الشفرة التي تعتمد عليها.
- نفس مشكلة التوافق مع asm.js والمزيد.
لذلك ، في النهاية ، لدينا حل وسط في شكل نوع بيانات منفصل جديد. يجدر التأكيد على أنه تم
بحث ومناقشة خيار آخر.
عندما تجلس على كرسيين
في الواقع ، يبدأ
تعليق اللجنة بالكلمات:
احصل على توازن بين الحفاظ على حدس المستخدم والحفاظ على الدقة
من ناحية ، أردت أخيرًا إضافة شيء "دقيق" إلى اللغة. ومن ناحية أخرى ، للحفاظ على سلوكها المألوف بالفعل للعديد من المطورين.
إنه فقط لا يمكن إضافة هذا "الدقيق" ، لأنه لا يمكنك كسره: الرياضيات ، وبيئة العمل اللغوية ، asm.js ،
وإمكانية التوسع في نظام الكتابة والإنتاجية ، وفي نهاية المطاف ، الويب نفسها! ولا يمكنك كسر كل شيء في نفس الوقت ، مما يؤدي إلى ذلك.
ولا يمكنك كسر حدس مستخدمي اللغة ، والتي كانت ، بالطبع ،
موضع نقاش ساخن . صحيح ، هل نجحت؟