التحقق من صحة الأرقام العشرية في JavaScript: لماذا يكسر IsNumeric() الكود وكيفية إصلاح ذلك
\n\nكل مطور كتب بلغة JavaScript لمدة أسبوع على الأقل، عاجلاً أم آجلاً، واجه مهمة: "التحقق مما إذا كانت السلسلة النصية رقماً". قد يبدو الأمر بسيطاً؟ الدالة المضمنة isNaN() أو parseFloat() وستكون المهمة منتهية. لكن الأمر ليس بهذه السهولة. سؤال "Validate decimal numbers in JavaScript — IsNumeric()" على Stack Overflow حصد مئات الآلاف من المشاهدات وعشرات الإجابات المتناقضة. لماذا؟ لأن JavaScript هي لغة حيث typeof NaN === 'number'، والسلسلة الفارغة تُعتبر صفراً.
في هذه المقالة، لن نقدم فقط دالة isNumeric() جاهزة. سنقوم بتحليل 5 أخطاء شائعة وخطيرة يرتكبها حتى المبرمجون ذوو الخبرة، وسنوضح كيفية تجنبها. ستتعرف على لماذا isNaN هو فخ، وكيف يعمل تحويل الأنواع، وأي طريقة للتحقق من صحة الأرقام في JS يجب استخدامها فعلياً في بيئة الإنتاج.
لماذا isNaN() شريرة (ومتى تعمل)
\n\nلنبدأ بالأمر الواضح. العديد من المبتدئين يكتبون هكذا:
\n\nfunction isNumeric(n) {\n return !isNaN(n);\n}\n\n\nللوهلة الأولى يبدو منطقياً: إذا لم يكن NaN، فهذا يعني أنه رقم. لكن دعنا نختبر:
\n\nconsole.log(isNumeric('123')); // true — صحيح\nconsole.log(isNumeric('12.3')); // true — صحيح\nconsole.log(isNumeric('')); // true — أوبس! السلسلة الفارغة رقم؟\nconsole.log(isNumeric(' ')); // true — المسافة أيضاً رقم؟\nconsole.log(isNumeric(null)); // true — null هو رقم؟\nconsole.log(isNumeric(true)); // true — true هو 1\n\n\nالخطأ رقم 1: isNaN() أولاً يحول الوسيطة إلى رقم، ثم يتحقق. السلسلة الفارغة '' تتحول إلى 0، null يتحول إلى 0، true يتحول إلى 1. ونتيجة لذلك، تعتبر الدالة ما ليس رقماً على أنه رقم.
هناك خيار صارم — Number.isNaN() (ES6)، لكنه يتحقق فقط مما إذا كانت القيمة هي NaN بالضبط، دون تحويل. وهو أيضاً غير مناسب للتحقق من صحة الأرقام.
parseFloat: بطل أم شرير؟
\n\nالنهج الشائع الثاني هو استخدام parseFloat():
function isNumeric(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n}\n\n\nهذا الخيار أفضل، لكن لديه مشكلة أخرى:
\n\nconsole.log(isNumeric('123abc')); // true — parseFloat سيأخذ '123' ويتجاهل 'abc'\nconsole.log(isNumeric('12.3.4')); // true — parseFloat لن يلاحظ النقطة الثانية\nconsole.log(isNumeric('Infinity')); // true — اللانهاية هل هي رقم؟\n\n\nالخطأ رقم 2: parseFloat() يحلل السلسلة حتى أول حرف غير صالح. السلسلة '123abc' بالنسبة له هي 123. لكن المستخدم ربما ضغط على مفتاح إضافي عن طريق الخطأ، ويجب علينا اكتشاف ذلك.
الخطأ رقم 3: isFinite() يستبعد Infinity و -Infinity، لكنه يسمح بمرور NaN و undefined. المشكلة هي أن isFinite(null) يُرجع true، لأن null يتحول إلى 0.
الخطأ رقم 4: التعبيرات المنتظمة — حل سحري أم جحيم جديد؟
\n\nعندما يدرك المطورون أن الدوال المضمنة غير موثوقة، غالباً ما يندفعون إلى الطرف الآخر — التعبيرات المنتظمة. وهنا تبدأ الفوضى الحقيقية.
\n\nإليك تعبير منتظم نموذجي ولكنه خطير:
\n\nfunction isNumeric(n) {\n return /^\\d+$/.test(n);\n}\n\n\nالمشاكل:
\n- \n
- لا يسمح بالنقاط العشرية (
'12.3'— false) \n - لا يسمح بالأرقام السالبة (
'-5'— false) \n - لا يسمح بالترميز العلمي (
'1e5'— false) \n
إليك "ال