isNaN()
الدالة isNaN()
تُحدِّد فيما إذا كانت القيمة المُمرَّرة إليها هي NaN
أم لا. لاحظ أنَّ تحويل القيم داخل الدالة isNaN()
له قواعد مثيرة للاهتمام؛ لذا يمكنك استخدام الدالة Number.isNaN()
التي عُرِّفَت في ECMAScript 2015 بدلًا من هذه الدالة.
البنية العامة
isNaN(value)
value
القيمة التي ستُختبَر إن كانت NaN
.
القيمة المعادة
القيمة true
إذا كانت القيمة المُعطاة هي NaN
، والقيمة false
فيما عدا ذلك.
الوصف
ضرورة وجود الدالة isNaN
على النقيض من بقية القيم في JavaScript، لا يمكن الاعتماد على معاملات المساواة (==
و ===
) لتحديد إذا كانت القيمة NaN
أم لا، لأنَّ قيمة التعبيرين NaN == NaN
و NaN === NaN
هي false
، وبالتالي هنالك حاجةٌ لهذه الدالة.
أصل قيم NaN
تولَّد قيم NaN
عندما تُنتِج العمليات الرياضية قيمًا غير معُرَّفة أو غير قابلة للتمثيل، وهذه القيمة تنتج أيضًا من محاولة تحويل القيم غير العددية قسريًا إلى قيم عددية والتي لا يمكن أن يكون لها تمثيلٌ عدديٌ أوليٌ.
فمثلًا، قسمة صفر على صفر ستُنتِج NaN
، لكن قسمة بقية الأعداد على الصفر لا تُنتِج NaN
.
السلوك المربك للحالة الخاصة للدالة isNaN
بدءًا من الإصدارات القديمة من مواصفة الدالة isNaN
كان سلوكها بالنسبة إلى الوسائط غير العددية مربكًا، فعندما لا يكون الوسيط المُمرَّر إلى الدالة isNaN
من النوع Number، فستحوَّل القيمة قسريًا إلى Number
، ثم ستُختبَر القيمة الناتجة لمعرفة إن كانت NaN
، وبالتالي عند تحويل القيم غير العددية إلى النوع Number
قسريًا فسينتج لدينا قيمة non-NaN عددية (ونخص بالذكر السلسلة النصية الفارغة والقيم المنطقية الأولية true
و false
، التي ستعطي القيم العددية 0 أو 1 عند تحويلها قسريًا إلى عدد) وستُعيد الدالة true
على الرغم من أننا نتوقع القيمة false
(فمن المؤكد أنَّ السلسلة النصية الفارغة -مثلًا- ليست رقمًا Not-A-Number).
ينشأ هذا السلوك المربك بسبب وجود معنى خاص للمصطلح «ليس عددًا» (Not-A-Number) للأرقام التي تُمثَّل كقيم IEEE-754 ذات فاصلة عائمة، ويجب أن تُفسَّر الدالة isNaN
على أنها إجابة عن التساؤل: «هل هذه القيمة، عند تحويلها قسريًا إلى قيمة عددية، هي قيمة Not-A-Number كما عرّفتها IEEE-754؟».
معيار ECMAScript 2015 أضاف الدالة Number.isNaN()
، واستخدام الدالة Number.isNaN(x)
هي طريقة عملية لمعرفة إن كانت القيمة x
هي NaN
أم لا، لكن تعريف NaN
سيبقى يحمل المعنى الرقمي ولن يعني «ليس رقمًا» (Not-A-Number)؛ ويمكن بشكلٍ بديل استخدام التعبير (x != x)
الذي يُعدّ أكثر طريقة عملية لمعرفة إن كانت القيمة x
هي NaN
أم لا، وستكون نتيجة التعبير السابقة غير خاضعة للحالات التي تجعل الدالة isNaN
غير عملية.
يمكن إنشاء حل التفافي للدالة isNaN
، عبر الاستفادة من خاصية عدم مساواة قيمة NaN
لنفسها:
var isNaN = function(value) {
var n = Number(value);
return n !== n;
};
أمثلة
هذه بعض الأمثلة عن القيم التي ستُعدّ Not-A-Number:
isNaN(NaN); // true
isNaN(undefined); // true
isNaN({}); // true
أما هذه فهي قيم ليست NaN:
isNaN(true); // false
isNaN(null); // false
isNaN(37); // false
أمثلة عن السلاسل النصية، لاحظ أنَّ السلسلة النصية "37"
في أوّل مثال قد حُوِّلَت إلى العدد 37
الذي ليس NaN
، وكذلك الأمر بالنسبة إلى 37.37
التي ستحوَّل إلى العدد 37.37
؛ أما السلسلة النصية "123ABC"
فهي NaN
وذلك لأنَّ ناتج Number("123ABC")
هو NaN
(على الرغم من أنَّ ناتج parseInt("123ABC")
هو 123
). آخر مثالين عن سلاسل نصية فارغة أو فيها فراغ وحيد، والتي ستحوّل إلى العدد 0
:
isNaN('37'); // false
isNaN('37.37'); // false
isNaN('123ABC'); // true
isNaN(''); // false
isNaN(' '); // false
مثال عن الكائن Date
، الذي سيُعيد رقمًا عند استخدامه مع الدالة البانية Number
، بينما ستكون السلسلة النصية التابعة له (والتي سنحصل عليها عبر الدالة toString
) هي NaN
:
isNaN(new Date()); // false
isNaN(new Date().toString()); // true
هذه نتيجة إيجبية كاذبة (false positive)، وهي السبب وراء كون الدالة isNaN
غير عملية تمامًا، وذلك لأنَّ السلسلة النصية "blabla"
ستحوّل إلى عدد، وتفسير هذا العدد سيفشل وستُعاد القيمة NaN
:
isNaN('blabla'); // true
السلوك المفيد للحالة الخاصة للدالة isNaN
هنالك طريقة يمكننا الاستفادة فيها من الدالة isNaN()
: فلو أعادت الدالة isNaN(x)
القيمة false
، فيمكننا استخدام x
كتعبير رياضي لا يُسبب إعادة القيمة NaN
، ولو أعادت true
فستؤدي القيمة x
إلى جعل جميع التعابير الرياضية التي تدخل فيها تُعيد القيمة NaN
؛ وهذا أنَّه في JavaScript إذا أعادت الدالة isNaN(x)
القيمة true
فهذا يعني أنَّ التعبير x - 0
(مثلًا) سيعيد القيمة NaN
(لكن التعبير x - 0 == NaN
سيعيد القيمة false
دومًا في JavaScript لأن NaN
لا تساوي نفسها، لذا لا يمكنك إجراء هذا الاختبار)، وفي الواقع ستُعيد الدوال isNaN(x)
و isNaN(x - 0)
و isNaN(Number(x))
و Number.isNaN(x - 0)
و Number.isNaN(Number(x))
القيمة نفسها؛ وأقصر طريقة للتعبير عنها هي استخدام الدالة isNaN(x)
.
يمكنك استخدام السلوك السابق لاختبار إذا كان الوسيط المُمرَّر إلى الدالة قابلًا للاستخدام في التعابير الرياضية (أي يمكن معاملته كعدد)، وإذا لم يكن كذلك فيمكنا توفير قيمة افتراضية أو اتباع إجراء آخر؛ وبهذه الطريقة ستستفيد الدالة من مرونة لغة JavaScript التي توفّرها عند تحويل القيم اعتمادًا على سياق استخدامها.
أمثلة
سنُعرِّف الدالة increment
، التي تُعيد ناتج إضافة القيمة 1
إلى الوسيط المُمرَّر إليها:
function increment(x) {
if (isNaN(x)) x = 0;
return x + 1;
}
// الدالة الآتية تكافئ الدالة السابقة
function increment(x) {
if (Number.isNaN(Number(x))) x = 0;
return x + 1;
}
في الحالات الآتية ستكون قيمة المعامل x
(أي الوسيط المُمرَّر إلى الدالة) ليست NaN
، لكن ليس من الضرورة أن تكون قيمة الوسيط عدديةً، وإنما يمكن استعمالها في التعابير الرياضية:
increment(''); // 1: "" => 0
increment(new String()); // 1: String object => 0
increment([]); // 1: [] => 0
increment(new Array()); // 1: Array object => 0
increment('0'); // 1: "0" => 0
increment('1'); // 2: "1" => 1
increment('0.1'); // 1.1: "0.1" => 0.1
increment('Infinity'); // Infinity: "Infinity" => Infinity
increment(null); // 1: null => 0
increment(false); // 1: false => 0
increment(true); // 2: true => 1
increment(new Date()); // تعيد الوقت والتاريخ الحاليين بالملي ثانية + 1
أما الحالات الآتية فتكون قيمة المعامل x
(أي الوسيط الممرر إلى الدالة) ليست NaN
، لكن الوسيط هو قيمةٌ عدديةٌ:
increment(-1); // 0
increment(-0.1); // 0.9
increment(0); // 1
increment(1); // 2
increment(2); // 3
// ... وهلم جرًا ...
increment(Infinity); // Infinity
أما في الحالات الآتيةـ فتكون نتيجة الدالة isNaN(x)
هي true
دومًا وقيمة الوسيط المُمرَّر إلى الدالة ليست عدديةً (Not-A-Number)، لذا ستضع الدالة القيمة 0 بدلًا منه (كما عرّفنا ذلك داخلها) والقيمة النهائية المعادة هي 1:
increment(String); // 1
increment(Array); // 1
increment('blabla'); // 1
increment('-blabla'); // 1
increment(0 / 0); // 1
increment('0 / 0'); // 1
increment(Infinity / Infinity); // 1
increment(NaN); // 1
increment(undefined); // 1
increment(); // 1
دعم المتصفحات
الميزة | Chrome | Firefox | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
الدعم الأساسي | نعم | نعم | نعم | نعم | نعم |
مصادر ومواصفات
- مسودة المعيار ECMAScript Latest Draft.
- معيار ECMAScript 2015 (6th Edition).
- معيار ECMAScript 5.1.
- معيار ECMAScript 1st Edition .