سؤال

لدي سؤال سريع (آمل!).في JS، لماذا isNaN(" ") تقييم كاذبة، ولكن isNaN(" x") تقييم صحيح؟

أقوم بإجراء عمليات رقمية في حقل إدخال النص، وأتحقق مما إذا كان الحقل خاليًا أو "" أو NaN.عندما يقوم شخص ما بكتابة مجموعة من المسافات في الحقل، يفشل التحقق من صحة البيانات الثلاثة، وأنا في حيرة من أمري بشأن سبب تجاوزها لفحص isNAN.

شكرًا!

هل كانت مفيدة؟

المحلول

وجافا سكريبت يفسر سلسلة فارغة بمثابة 0، والذي ثم فشل اختبار isNAN. يمكنك استخدام parseInt على السلسلة لأول مرة والتي سوف يتم تحويل سلسلة فارغة إلى 0. نتيجة ينبغي بعد فشل isNAN.

نصائح أخرى

وأنت قد تجد هذه الدهشة أو ربما لا، ولكن هنا بعض رمز اختبار لتظهر لك wackyness من محرك جافا سكريبت.

document.write(isNaN("")) // false
document.write(isNaN(" "))  // false
document.write(isNaN(0))  // false
document.write(isNaN(null)) // false
document.write(isNaN(false))  // false
document.write("" == false)  // true
document.write("" == 0)  // true
document.write(" " == 0)  // true
document.write(" " == false)  // true
document.write(0 == false) // true
document.write(" " == "") // false

وهكذا وهذا يعني أن

" " == 0 == false

و

"" == 0 == false

ولكن

"" != " "

والمتعة:)

لفهم ذلك بشكل أفضل، يرجى فتح مواصفات Ecma-Script pdf في الصفحة 43 "تم تطبيق ToNumber على نوع السلسلة"

إذا كانت السلسلة تحتوي على بناء جملة رقمي، والذي يمكن أن يحتوي على أي عدد من أحرف المسافة البيضاء، فيمكن تحويلها إلى نوع رقم.يتم تقييم السلسلة الفارغة إلى 0.كما يجب أن تعطي السلسلة "Infinity".

isNaN('Infinity'); // false

وحاول استخدام:

alert(isNaN(parseInt("   ")));

أو

alert(isNaN(parseFloat("    ")));

MDN سبب المشكلة التي تواجه

<اقتباس فقرة>   

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

وأنت قد ترغب في التحقق من إجابة شاملة التالي الذي يغطي مقارنة نان من أجل المساواة أيضا.

<اقتباس فقرة>   

كيفية اختبار إذا متغير جافا سكريبت غير NaN

واعتقد انها بسبب الكتابة جافا سكريبت ل: يتم تحويل ' ' إلى الصفر، في حين 'x' ليس:

alert(' ' * 1); // 0
alert('x' * 1); // NaN

إذا كنت ترغب في تنفيذ وظيفة ISNUMBER دقيقة، وهنا هو واحد طريقة للقيام بذلك من جافا سكريبت: أجزاء جيدة من جانب دوغلاس كروكفورد [صفحة 105]

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}

الإجابة غير الصحيحة تمامًا

أنطونيو هالي إجابة عالية التصويت ومقبولة هنا يفترض خطأً أن هذه العملية تمر عبر JavaScript parseInt وظيفة:

يمكنك استخدام parseInt على السلسلة ...يجب أن تفشل النتيجة بعد ذلك في NAN.

يمكننا بسهولة دحض هذا البيان باستخدام السلسلة "123abc":

parseInt("123abc")    // 123     (a number...
isNaN("123abc")       // true     ...which is not a number)

وبهذا، يمكننا أن نرى أن JavaScript parseInt إرجاع الوظيفة "123abc" كرقم 123, ، ومع ذلك isNaN الوظيفة تخبرنا بذلك "123abc" ليس كذلك رقم.

الجواب الصحيح

يحدد ECMAScript-262 كيفية عمل isNaN تحقق من العمل في القسم 18.2.3.

18.2.3 isNaN (رقم)

ال isNaN الوظيفة هي %isNaN% كائن جوهري.عندما isNaN يتم استدعاء الدالة برقم وسيطة واحدة، ويتم اتباع الخطوات التالية:

  1. يترك num يكون ؟ ToNumber(number).
  2. لو num يكون NaN, ، يعود true.
  3. وإلا ارجع false.

ال ToNumber يتم تعريف الوظيفة التي تشير إليها أيضًا قسم ECMAScript-262 7.1.3.هنا، يتم إخبارنا كيف تتعامل JavaScript مع السلاسل التي يتم تمريرها إلى هذه الوظيفة.

المثال الأول الوارد في السؤال هو سلسلة لا تحتوي إلا على أحرف مسافة بيضاء.ينص هذا القسم على ما يلي:

أ StringNumericLiteral يتم تحويله إلى ما هو فارغ أو يحتوي على مسافة بيضاء فقط +0.

ال " " وبالتالي يتم تحويل سلسلة المثال إلى +0, ، وهو رقم.

وينص نفس القسم أيضًا على:

إذا لم يتمكن النحو من تفسير String كتوسيع ل StringNumericLiteral, ، ثم النتيجة ToNumber يكون NaN.

دون الاقتباس من جميع الشيكات الواردة في هذا القسم، فإن " x" المثال الوارد في السؤال يندرج في الشرط أعلاه لأنه لا يمكن تفسيره على أنه أ StringNumericLiteral. " x" وبالتالي يتم تحويلها إلى NaN.

ولست متأكدا <م> لماذا ، ولكن للالتفاف على المشكلة التي يمكن دائما تقليم بيضاء قبل التحقق. وربما كنت تريد أن تفعل ذلك على أي حال.

الوظيفة isNaN("") ينفذ أ سلسلة إلى رقم نوع الإكراه

يحدد ECMAScript 3-5 قيم الإرجاع التالية لعامل التشغيل typeof:

  • غير معرف
  • كائن (فارغ، كائنات، صفائف)
  • منطقية
  • رقم
  • خيط
  • وظيفة

من الأفضل أن نلف اختبارنا في نص وظيفي:

function isNumber (s) {
    return typeof s == 'number'? true
           : typeof s == 'string'? (s.trim() === ''? false : !isNaN(s))
           : (typeof s).match(/object|function/)? false
           : !isNaN(s)
}

هذه الوظيفة ليست مخصصة لاختبار المتغير يكتب, ، بدلاً من ذلك يقوم باختبار القيمة القسرية.على سبيل المثال، يتم فرض القيم المنطقية والسلاسل النصية على أرقام، لذا ربما ترغب في استدعاء هذه الوظيفة باسم isNumberCoerced()

إذا لم تكن هناك حاجة لاختبار أنواع غير ذلك خيط و رقم, ، فيمكن استخدام المقتطف التالي كجزء من بعض الشروط:

if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
    alert("s is a number")

وأنا أقترح عليك استخدام الدالة التالية إذا كنت تريد حقا الاختيار الصحيح إذا كان هو عدد صحيح:

function isInteger(s)
{
   return Math.ceil(s) == Math.floor(s);
}

الذي - التي isNaN(" ") يعتبر خطأ جزءًا من السلوك المربك لـ isNaN دالة عالمية بسبب إكراهها غير الأرقام على نوع رقمي.

من MDN:

منذ الإصدارات الأولى من isNaN مواصفات الوظيفة، كان سلوكها للوسائط غير الرقمية مربكًا.عندما الحجة إلى isNaN الدالة ليست من النوع رقم، حيث يتم فرض القيمة أولاً على رقم.ثم يتم اختبار القيمة الناتجة لتحديد ما إذا كانت كذلك NaN.وبالتالي بالنسبة للأرقام غير الرقمية التي عند إكراهها على النوع الرقمي تؤدي إلى قيمة رقمية صالحة غير NaN (لا سيما السلسلة الفارغة والأوليات المنطقية، والتي عند الإكراه تعطي قيمًا رقمية صفر أو واحد)، قد تكون القيمة المرجعة "الخاطئة" غير متوقعة؛على سبيل المثال، السلسلة الفارغة هي بالتأكيد "ليست رقمًا".

لاحظ أيضًا أنه مع ECMAScript 6، يوجد الآن أيضًا Number.isNaN الطريقة التي وفقًا لـ MDN:

بالمقارنة مع العالمية isNaN() وظيفة، Number.isNaN() لا يعاني من مشكلة تحويل المعلمة بقوة إلى رقم.وهذا يعني أنه أصبح من الآمن الآن تمرير القيم التي يتم التحويل إليها عادةً NaN, ، ولكنها ليست في الواقع نفس القيمة مثل NaN.وهذا يعني أيضًا أن قيم رقم النوع فقط هي أيضًا NaN, ، يعود true.

للأسف:

حتى ECMAScript 6 Number.isNaN الطريقة لها مشكلاتها الخاصة، كما هو موضح في منشور المدونة - إصلاح مشكلة JavaScript وES6 NaN القبيحة.

وكما هو موضح الآخر فإن وظيفة isNaN إكراه سلسلة فارغة إلى الرقم قبل التحقق من صحة ذلك، وبالتالي تغيير سلسلة فارغة إلى 0 (والذي هو رقم صحيح). ومع ذلك، وجدت أن وظيفة parseInt سيعود NaN عند محاولة تحليل سلسلة فارغة أو سلسلة مع المسافات فقط. كما يبدو مثل التركيبة التالية أن تعمل بشكل جيد:

وif ( isNaN(string) || isNaN(parseInt(string)) ) console.log('Not a number!');

وهذا الاختيار يعمل الأرقام الموجبة الأرقام السالبة وأرقام مع نقطة العشرية، لذلك أعتقد أنه يغطي جميع الحالات العددية المشتركة.

وهذه الوظيفة يبدو أن العمل في بلدي التجارب

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}

وماذا عن

function isNumberRegex(value) {        
    var pattern = /^[-+]?\d*\.?\d*$/i;
    var match = value.match(pattern);
    return value.length > 0 && match != null;
}

ال isNaN تتوقع الدالة رقمًا كوسيطة لها، لذلك سيتم تحويل الوسيطات من أي نوع آخر (في حالتك سلسلة) إلى رقم قبل يتم تنفيذ منطق الوظيفة الفعلي.(انتبه أن NaN هي أيضًا قيمة من النوع Number!)

بالمناسبة.هذا أمر شائع بالنسبة ل الجميع الوظائف المضمنة - إذا كانوا يتوقعون وسيطة من نوع معين، فسيتم تحويل الوسيطة الفعلية باستخدام وظائف التحويل القياسية.هناك تحويلات قياسية بين جميع الأنواع الأساسية (منطقي، سلسلة، رقم، كائن، تاريخ، فارغ، غير محدد.)

التحويل القياسي ل String ل Number يمكن الاحتجاج صريحا مع Number().لذلك يمكننا أن نرى أن:

  • Number(" ") يقيم ل 0
  • Number(" x") يقيم ل NaN

ونظرا لهذا، فإن نتيجة isNaN الوظيفة منطقية تمامًا!

السؤال الحقيقي هو لماذا يعمل التحويل القياسي من سلسلة إلى رقم بهذه الطريقة.إن المقصود من تحويل السلسلة إلى رقم هو تحويل السلاسل الرقمية مثل "123" أو "17.5e4" إلى أرقام مكافئة.يتخطى التحويل أولاً المسافة البيضاء الأولية (بحيث يكون "123" صالحًا) ثم يحاول تحليل المساند كرقم.إذا لم يكن قابلاً للتحليل كرقم ("x" ليس كذلك) فإن النتيجة هي NaN.ولكن هناك قاعدة خاصة صريحة مفادها أن السلسلة الفارغة أو المسافة البيضاء فقط يتم تحويلها إلى 0.وهذا ما يفسر التحويل.

مرجع: http://www.ecma-international.org/ecma-262/5.1/#sec-9.3.1

ولقد كتبت هذه الوظيفة قليلا سريعة للمساعدة في حل هذه المشكلة.

function isNumber(val) {
     return (val != undefined && val != null && val.toString().length > 0 && val.toString().match(/[^0-9\.\-]/g) == null);
};

وببساطة بالتحقق من أي أحرف غير رقمية (0-9)، التي ليست '-' '.' أو، والتي ليست غير محددة، خالية أو فارغة وإرجاع حقيقية اذا لم يكن هناك مباريات. :)

ال جافا سكريبت مدمج isNaN الوظيفة، كما هو متوقع افتراضيًا، هي "عامل النوع الديناميكي".لذلك جميع القيم التي (أثناء عملية DTC) قد تسفر عن صحيح بسيط | خطأ مثل "", " ", " 000", ، لا يمكن أن يكون NaN.

بمعنى أن دعوى الموردة سوف تخضع أولا ل تحويل كما في:

function isNaNDemo(arg){
   var x = new Number(arg).valueOf();
   return x != x;
}

توضيح:

في السطر العلوي من نص الدالة، نحاول (أولاً) تحويل الوسيطة بنجاح إلى كائن رقمي.و(ثانيًا)، باستخدام عامل النقطة، فإننا - من أجل راحتنا - نقوم بالتجريد على الفور، ال بدائية قيمة للكائن الذي تم إنشاؤه.

في السطر الثاني، نأخذ القيمة التي تم الحصول عليها في الخطوة السابقة، وميزة ذلك نان لا يساوي شيئًا في الكون، ولا حتى نفسه، مثال: NaN == NaN >> false ليقارنه أخيرًا (للتفاوت) مع نفسه.

بهذه الطريقة سوف تسفر عودة الدالة حقيقي فقط عندما، وفقط إذا كانت وسيطة الإرجاع المتوفرة، عبارة عن محاولة فاشلة للتحويل إلى كائن رقم، أي رقم ليس رقمًا؛على سبيل المثال، نان.


isNaNstatic()

ومع ذلك، بالنسبة لمشغل النوع الثابت - إذا لزم الأمر وعند الحاجة - يمكننا كتابة دالة أبسط بكثير مثل:

function isNaNstatic(x){   
   return x != x;
}

وتجنب DTC تمامًا، بحيث إذا لم تكن الوسيطة رقم NaN بشكل صريح، فسوف تُرجع خطأ.ولذلك، اختبار ضد ما يلي:

isNaNStatic(" x"); // will return false لأنها لا تزال سلسلة.

لكن:isNaNStatic(1/"x"); // will of course return true. كما سوف على سبيل المثال isNaNStatic(NaN); >> true.

ولكن على خلاف ذلك isNaN, ، ال isNaNStatic("NaN"); >> false لأنها (الحجة) سلسلة عادية.

ملاحظة.:يمكن أن يكون الإصدار الثابت من isNaN مفيدًا جدًا في سيناريوهات الترميز الحديثة.وقد يكون هذا أحد الأسباب الرئيسية التي دفعتني إلى قضاء وقتي في نشر هذا.

يعتبر.

وisNAN(<argument>) هي وظيفة لمعرفة ما إذا كان حجة معين هو عدد غير قانوني. isNaN typecasts الحجج إلى نوع الرقم. إذا كنت ترغب في معرفة ما اذا كان الحجة رقمية أم لا؟ الرجاء استخدام وظيفة $.isNumeric() في مسج.

وهذا هو، isNaN (فو) ما يعادل isNaN (عدد (فو)) أنه يقبل أي سلاسل وجود جميع الأرقام كأرقام لأسباب واضحة. لالسابقين.

isNaN(123) //false
isNaN(-1.23) //false
isNaN(5-2) //false
isNaN(0) //false
isNaN('123') //false
isNaN('Hello') //true
isNaN('2005/12/12') //true
isNaN('') //false
isNaN(true) //false
isNaN(undefined) //true
isNaN('NaN') //true
isNaN(NaN) //true
isNaN(0 / 0) //true

وأنا استخدم هذا

    function isNotANumeric(val) {
    	if(val.trim && val.trim() == "") {
         return true;
      } else {
      	 return isNaN(parseFloat(val * 1));
      }
    }
    
    alert(isNotANumeric("100"));  // false
    alert(isNotANumeric("1a"));   // true
    alert(isNotANumeric(""));     // true
    alert(isNotANumeric("   "));  // true

وNaN! == "ليس عددا"

وNaN هو قيمة نوع الرقم

وهذا هو تعريف isNaN () في ECMAScript

1. Let num be ToNumber(number).
2. ReturnIfAbrupt(num).
3. If num is NaN, return true.
4. Otherwise, return false.

ومحاولة لتحويل أي قيمة إلى رقم.

Number(" ") // 0
Number("x") // NaN
Number(null) // 0

إذا كنت ترغب في تحديد ما إذا كانت القيمة NaN، يجب أن تحاول تحويله إلى قيمة عدد أولا.

عند التحقق إذا قيمة سلسلة معينة مع بيضاء أو " "is isNaN ربما يحاول إجراء التحقق من الصحة سلسلة، على سبيل المثال:

و// value = "123 " if (value.match(/\s/) || isNaN(value)) { // do something }

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top