توليد الأعداد الصحيحة العشوائية في JavaScript: نطاق دقيق في 2025

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

الأعداد العشوائية في JavaScript: من الفوضى إلى النظام

\n

تخيل: أنت تكتب لعبة تحتاج فيها إلى اختيار صندوق كنز بشكل عشوائي من 1 إلى 100. أو ربما تقوم بإنشاء اختبار A/B يختار خيارًا عشوائيًا للمستخدم. قد يبدو الأمر بسيطًا، أليس كذلك؟ لكن الشيطان، كما هو الحال دائمًا، يكمن في التفاصيل. مسألة توليد الأعداد الصحيحة العشوائية في JavaScript في نطاق محدد هي واحدة من أكثر الأسئلة شيوعًا على Stack Overflow، وليس من دون سبب. حتى المطورون ذوو الخبرة يتعثرون أحيانًا في مخاطر Math.random().

\n

في هذه المقالة، سنقوم بتحليل ليس فقط الطرق الكلاسيكية، ولكن أيضًا أفضل الممارسات لعام 2025: كيفية جعل الكود ليس فقط فعالاً، بل أيضًا آمنًا، وقابلاً للتنبؤ (بالمعنى الجيد)، وفعالاً من حيث الأداء. هيا بنا!

\n\n

كلاسيكيات النوع: Math.random() والمخاطر الخفية

\n

لنبدأ بالأساسيات. الدالة المضمنة Math.random() تُرجع رقمًا عشريًا شبه عشوائي في النطاق [0, 1). النقطة الأساسية: يتم تضمين 0، ولكن لا يتم تضمين 1. هذا توزيع "غير عادل" إذا كنت ترغب في الحصول على أعداد صحيحة.

\n

إليك الطريقة الأكثر شيوعًا (والأكثر خطأ) التي توجد غالبًا في الكتب الدراسية القديمة:

\n
// مثال سيء: انحياز في الاحتمالية\nfunction getRandomBad(min, max) {\n  return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n
\n

للوهلة الأولى، يبدو كل شيء صحيحًا. لكن دعنا نتعمق أكثر. Math.floor() يُقرّب إلى الأسفل. إذا قام Math.random() بتوليد رقم قريب جدًا من 1 (ولكن ليس مساويًا له)، فإن الضرب في (max - min + 1) سيعطي قيمة أقل من max + 1، وسيقوم Math.floor() بقطعها. ومع ذلك، نظرًا للدقة المحدودة للأعداد العشرية (IEEE 754)، تظهر بعض القيم بشكل أقل من غيرها. بالنسبة للنطاق 0-1، هذا غير ملحوظ، ولكن بالنسبة للنطاقات الكبيرة (على سبيل المثال، من 1 إلى 1,000,000)، يصبح الانحياز ذا دلالة إحصائية.

\n

الخلاصة: هذه الصيغة تعمل مع النطاقات الصغيرة، لكنها ليست "نقية تشفيريًا" وقد تؤدي إلى انحراف في التوزيع.

\n\n

الصيغة الصحيحة من MDN

\n

توصي شبكة مطوري Mozilla (MDN) بنهج أكثر دقة يقلل من أخطاء التقريب:

\n
// طريقة جيدة وعالمية\nfunction getRandomIntInclusive(min, max) {\n  const minCeiled = Math.ceil(min);\n  const maxFloored = Math.floor(max);\n  return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled);\n}\n
\n

الفرق هو أننا نقوم بتحويل الحدود بشكل صريح إلى أعداد صحيحة باستخدام Math.ceil() و Math.floor(). هذا يضمن معالجة min و max بشكل صحيح، حتى إذا قمت بتمرير رقم عشري عن طريق الخطأ. استخدم هذه الطريقة كمعيار أساسي في عام 2025.

\n\n

البدائل: عندما لا يكون Math.random() كافيًا

\n

إن Math.random() الكلاسيكي هو مولد شبه عشوائي (PRNG). إنه حتمي: إذا كنت تعرف البذرة الأولية (seed)، يمكنك توقع التسلسل بأكمله. بالنسبة لمعظم تطبيقات الويب (الرسوم المتحركة، المحتوى العشوائي)، هذا كافٍ. ولكن هناك سيناريوهات تحتاج فيها إلى عشوائية حقيقية:

\n
    \n
  • الأمان: توليد الرموز المميزة (tokens)، كلمات المرور، رموز CSRF.
  • \n
  • التشفير: تشفير البيانات على جهة العميل.
  • \n
  • ألعاب القمار: توزيع عادل للمكاسب.
  • \n
\n

في هذه الحالات، يأتي crypto.getRandomValues() للإنقاذ - وهو مولد قوي تشفيريًا (CSPRNG). يستخدم مصادر إنتروبيا النظام ويكون أقل قابلية للتنبؤ بكثير.

\n\n

توليد الأعداد الصحيحة باستخدام crypto.getRandomValues()

\n

إليك كيف يبدو التنفيذ الحديث لعام 2025:

\n
// توليد آمن لعدد صحيح عشوائي في النطاق [min, max]\nfunction getSecureRandomInt(min, max) {\n  const range = max - min + 1;\n  // القيمة القصوى التي هي من مضاعفات range (لتجنب الانحياز                

المدونات

توصيات الكتب