الدليل الأساسي لنوع بيانات JavaScript الأحدث: BigInt

نشرت: 2022-03-10
ملخص سريع ↬ في JavaScript ، لا يمكن لنوع Number أن يمثل بأمان قيمًا أكبر من 2 53 . أجبر هذا القيد المطورين على استخدام الحلول غير الفعالة ومكتبات الجهات الخارجية. BigInt هو نوع بيانات جديد يهدف إلى إصلاح ذلك.

يهدف نوع بيانات BigInt إلى تمكين مبرمجي JavaScript من تمثيل قيم عدد صحيح أكبر من النطاق الذي يدعمه نوع البيانات Number . تعتبر القدرة على تمثيل الأعداد الصحيحة بدقة عشوائية مهمة بشكل خاص عند إجراء عمليات حسابية على أعداد صحيحة كبيرة. مع BigInt ، لن يكون تجاوز العدد الصحيح مشكلة.

بالإضافة إلى ذلك ، يمكنك العمل بأمان باستخدام طوابع زمنية عالية الدقة ومعرفات أعداد صحيحة كبيرة والمزيد دون الحاجة إلى استخدام حل بديل. BigInt هو حاليًا اقتراح من المرحلة 3. بمجرد إضافته إلى المواصفات ، سيصبح نوع البيانات الرقمية الثاني في JavaScript ، مما سيجعل العدد الإجمالي لأنواع البيانات المدعومة ثمانية:

  • قيمة منطقية
  • باطل
  • غير معرف
  • رقم
  • BigInt
  • سلسلة
  • رمز
  • موضوع

في هذه المقالة ، سوف نلقي نظرة فاحصة على BigInt ونرى كيف يمكن أن تساعد في التغلب على قيود نوع Number في JavaScript.

المشكلة

غالبًا ما يكون الافتقار إلى نوع عدد صحيح واضح في JavaScript محيرًا للمبرمجين القادمين من لغات أخرى. تدعم العديد من لغات البرمجة أنواعًا رقمية متعددة مثل float ، و double ، و number number ، و bignum ، ولكن هذا ليس هو الحال مع JavaScript. في JavaScript ، يتم تمثيل جميع الأرقام بتنسيق فاصلة عائمة 64 بت مزدوج الدقة كما هو محدد بواسطة معيار IEEE 754-2008.

المزيد بعد القفز! أكمل القراءة أدناه ↓

وفقًا لهذا المعيار ، يتم تقريب الأعداد الصحيحة الكبيرة جدًا التي لا يمكن تمثيلها بدقة. على وجه الدقة ، يمكن أن يمثل نوع Number في JavaScript فقط بأمان الأعداد الصحيحة بين -9007199254740991 (- (2 53 -1)) و 9007199254740991 (2 53 -1). قد تفقد أي قيمة عدد صحيح يقع خارج هذا النطاق الدقة.

يمكن فحص ذلك بسهولة عن طريق تنفيذ الكود التالي:

 console.log(9999999999999999); // → 10000000000000000

هذا العدد الصحيح أكبر من أكبر عدد يمكن أن يمثله JavaScript بشكل موثوق باستخدام Number البدائي. لذلك ، يتم تقريبها. يمكن أن يؤدي التقريب غير المتوقع إلى تعريض موثوقية البرنامج وأمانه للخطر. إليك مثال آخر:

 // notice the last digits 9007199254740992 === 9007199254740993; // → true

توفر JavaScript ثابت Number.MAX_SAFE_INTEGER الذي يسمح لك بالحصول بسرعة على أقصى عدد صحيح آمن في JavaScript. وبالمثل ، يمكنك الحصول على الحد الأدنى من عدد صحيح آمن باستخدام Number.MIN_SAFE_INTEGER ثابت:

 const minInt = Number.MIN_SAFE_INTEGER; console.log(minInt); // → -9007199254740991 console.log(minInt - 5); // → -9007199254740996 // notice how this outputs the same value as above console.log(minInt - 4); // → -9007199254740996

الحل

كحل بديل لهذه القيود ، يمثل بعض مطوري JavaScript أعدادًا صحيحة كبيرة باستخدام نوع String . تضيف Twitter API ، على سبيل المثال ، إصدار سلسلة من المعرفات للكائنات عند الاستجابة باستخدام JSON. بالإضافة إلى ذلك ، تم تطوير عدد من المكتبات مثل bignumber.js لتسهيل العمل مع أعداد صحيحة كبيرة.

باستخدام BigInt ، لم تعد التطبيقات بحاجة إلى حل بديل أو مكتبة لتمثيل أعداد صحيحة بأمان تتجاوز Number.MAX_SAFE_INTEGER و Number.Min_SAFE_INTEGER . يمكن الآن إجراء العمليات الحسابية على أعداد صحيحة كبيرة في JavaScript قياسي دون المخاطرة بفقدان الدقة. الميزة الإضافية لاستخدام نوع بيانات أصلي على مكتبة تابعة لجهة خارجية هي أداء وقت تشغيل أفضل.

لإنشاء BigInt ، قم ببساطة بإلحاق n بنهاية عدد صحيح. قارن:

 console.log(9007199254740995n); // → 9007199254740995n console.log(9007199254740995); // → 9007199254740996

بدلاً من ذلك ، يمكنك استدعاء مُنشئ BigInt() :

 BigInt("9007199254740995"); // → 9007199254740995n

يمكن أيضًا كتابة BigInt literals بتدوين ثنائي أو ثماني أو سداسي عشري:

 // binary console.log(0b100000000000000000000000000000000000000000000000000011n); // → 9007199254740995n // hex console.log(0x20000000000003n); // → 9007199254740995n // octal console.log(0o400000000000000003n); // → 9007199254740995n // note that legacy octal syntax is not supported console.log(0400000000000000003n); // → SyntaxError

ضع في اعتبارك أنه لا يمكنك استخدام عامل تشغيل المساواة الصارمة لمقارنة BigInt برقم عادي لأنهما ليسا من نفس النوع:

 console.log(10n === 10); // → false console.log(typeof 10n); // → bigint console.log(typeof 10); // → number

بدلاً من ذلك ، يمكنك استخدام عامل المساواة ، الذي يقوم بإجراء تحويل ضمني للنوع قبل إجراء معاملاته:

 console.log(10n == 10); // → true

يمكن استخدام جميع المعاملات الحسابية على BigInt s باستثناء عامل الجمع الأحادي ( + ):

 10n + 20n; // → 30n 10n - 20n; // → -10n +10n; // → TypeError: Cannot convert a BigInt value to a number -10n; // → -10n 10n * 20n; // → 200n 20n / 10n; // → 2n 23n % 10n; // → 3n 10n ** 3n; // → 1000n let x = 10n; ++x; // → 11n --x; // → 10n

السبب في عدم دعم عامل التشغيل أحادي زائد ( + ) هو أن بعض البرامج قد تعتمد على الثابت الذي ينتج عنه + دائمًا Number ، أو يطرح استثناءً. سيؤدي تغيير سلوك + أيضًا إلى كسر كود asm.js.

بطبيعة الحال ، عند استخدامها مع معاملات BigInt ، من المتوقع أن تُرجع العوامل الحسابية قيمة BigInt . لذلك ، يتم اقتطاع نتيجة عامل القسمة ( / ) تلقائيًا. علي سبيل المثال:

 25 / 10; // → 2.5 25n / 10n; // → 2n

نوع التحويل الضمني

نظرًا لأن تحويل النوع الضمني قد يفقد المعلومات ، لا يُسمح بالعمليات المختلطة بين BigInt s و Number s. عند مزج الأعداد الصحيحة الكبيرة وأرقام الفاصلة العائمة ، قد لا يتم تمثيل القيمة الناتجة بدقة بواسطة BigInt أو Number . ضع في اعتبارك المثال التالي:

 (9007199254740992n + 1n) + 0.5

تكون نتيجة هذا التعبير خارج مجال كل من BigInt و Number . لا يمكن تحويل Number بجزء كسري بدقة إلى BigInt . ولا يمكن تحويل BigInt الأكبر من 2 53 إلى Number بدقة.

نتيجة لهذا التقييد ، لا يمكن إجراء عمليات حسابية بمزيج من معاملات Number و BigInt . لا يمكنك أيضًا تمرير BigInt إلى واجهات برمجة تطبيقات الويب ووظائف JavaScript المضمنة التي تتوقع Number . ستؤدي محاولة القيام بذلك إلى حدوث خطأ في TypeError :

 10 + 10n; // → TypeError Math.max(2n, 4n, 6n); // → TypeError

لاحظ أن العوامل الارتباطية لا تتبع هذه القاعدة ، كما هو موضح في هذا المثال:

 10n > 5; // → true

إذا كنت تريد إجراء عمليات حسابية باستخدام BigInt و Number ، فأنت بحاجة أولاً إلى تحديد المجال الذي يجب إجراء العملية فيه. للقيام بذلك ، قم ببساطة بتحويل أي من المعاملين عن طريق استدعاء Number() أو BigInt() :

 BigInt(10) + 10n; // → 20n // or 10 + Number(10n); // → 20

عند مواجهتها في سياق Boolean ، يتم التعامل مع BigInt بطريقة مماثلة لـ Number . بعبارة أخرى ، تعتبر BigInt قيمة صادقة طالما أنها ليست 0n :

 if (5n) { // this code block will be executed } if (0n) { // but this code block won't }

لا يحدث تحويل نوع ضمني بين أنواع BigInt و Number عند فرز مصفوفة:

 const arr = [3n, 4, 2, 1n, 0, -1n]; arr.sort(); // → [-1n, 0, 1n, 2, 3n, 4]

عوامل Bitwise مثل | & << و >> و ^ على BigInt s بطريقة مشابهة لـ Number s. يتم تفسير الأعداد السالبة على أنها تكملة لا نهائية لاثنين. المعاملات المختلطة غير مسموح بها. وهنا بعض الأمثلة:

 90 | 115; // → 123 90n | 115n; // → 123n 90n | 115; // → TypeError

منشئ BigInt

كما هو الحال مع الأنواع الأولية الأخرى ، يمكن إنشاء BigInt باستخدام دالة مُنشئ. يتم تحويل الوسيطة التي تم تمريرها إلى BigInt() تلقائيًا إلى BigInt ، إذا أمكن:

 BigInt("10"); // → 10n BigInt(10); // → 10n BigInt(true); // → 1n

أنواع البيانات والقيم التي لا يمكن تحويلها بطرح استثناء:

 BigInt(10.2); // → RangeError BigInt(null); // → TypeError BigInt("abc"); // → SyntaxError

يمكنك إجراء عمليات حسابية مباشرة على BigInt تم إنشاؤه باستخدام المُنشئ:

 BigInt(10) * 10n; // → 100n

عند استخدامها كمعامِلات لمشغل المساواة الصارمة ، يتم التعامل مع BigInt التي تم إنشاؤها باستخدام مُنشئ على غرار المعاملات العادية:

 BigInt(true) === 1n; // → true

وظائف المكتبة

يوفر JavaScript وظيفتين للمكتبة لتمثيل قيم BigInt صحيحة موقعة أو بدون إشارة:

  • BigInt.asUintN(width, BigInt) BigInt التفاف كبير بين 0 و 2 عرض -1
  • BigInt.asIntN(width, BigInt) BigInt التفاف كبير بين -2 عرض -1 و 2 عرض -1 -1

هذه الوظائف مفيدة بشكل خاص عند إجراء عمليات حسابية 64 بت. بهذه الطريقة يمكنك البقاء ضمن النطاق المقصود.

دعم المتصفح و Transpiling

في وقت كتابة هذه السطور ، كان Chrome +67 و Opera +54 يدعمان تمامًا نوع بيانات BigInt . لسوء الحظ ، فإن Edge و Safari لم ينفذهما بعد. لا يدعم Firefox BigInt افتراضيًا ، ولكن يمكن تمكينه عن طريق تعيين javascript.options.bigint على true في about:config . قائمة محدثة من المتصفحات المدعومة متاحة على Can I use….

لسوء الحظ ، يعد تحويل BigInt عملية معقدة للغاية ، والتي تؤدي إلى عقوبة أداء كبيرة في وقت التشغيل. من المستحيل أيضًا تعويض BigInt بشكل مباشر لأن الاقتراح يغير سلوك العديد من المشغلين الحاليين. في الوقت الحالي ، هناك بديل أفضل وهو استخدام مكتبة JSBI ، وهي عبارة عن تطبيق JavaScript خالص لاقتراح BigInt .

توفر هذه المكتبة واجهة برمجة تطبيقات تتصرف تمامًا مثل BigInt الأصلي. إليك كيفية استخدام JSBI:

 import JSBI from './jsbi.mjs'; const b1 = JSBI.BigInt(Number.MAX_SAFE_INTEGER); const b2 = JSBI.BigInt('10'); const result = JSBI.add(b1, b2); console.log(String(result)); // → '9007199254741001'

تتمثل إحدى ميزات استخدام JSBI في أنه بمجرد تحسين دعم المتصفح ، فلن تحتاج إلى إعادة كتابة التعليمات البرمجية الخاصة بك. بدلاً من ذلك ، يمكنك ترجمة كود JSBI تلقائيًا إلى رمز BigInt الأصلي باستخدام مكون Babel الإضافي. علاوة على ذلك ، يتساوى أداء JSBI مع تطبيقات BigInt الأصلية. يمكنك توقع دعم متصفح أوسع لـ BigInt قريبًا.

خاتمة

BigInt هو نوع بيانات جديد مخصص للاستخدام عندما تكون قيم الأعداد الصحيحة أكبر من النطاق الذي يدعمه نوع البيانات Number . يتيح لنا نوع البيانات هذا إجراء عمليات حسابية بأمان على أعداد صحيحة كبيرة ، وتمثيل طوابع زمنية عالية الدقة ، واستخدام معرفات أعداد صحيحة كبيرة ، والمزيد دون الحاجة إلى استخدام مكتبة.

من المهم أن تضع في اعتبارك أنه لا يمكنك إجراء عمليات حسابية بمزيج من معاملات Number و BigInt . ستحتاج إلى تحديد المجال الذي يجب إجراء العملية فيه عن طريق التحويل الصريح لأي من المعاملين. علاوة على ذلك ، لأسباب تتعلق بالتوافق ، لا يُسمح لك باستخدام عامل التشغيل أحادي زائد ( + ) على BigInt .

ما رأيك؟ هل تجد BigInt مفيدًا؟ اسمحوا لنا أن نعرف في التعليقات!