Чому isNaN (“”) (рядок з пробілами) дорівнює false?


160

Чому у JavaScript чому isNaN(" ")оцінюють false, а чи isNaN(" x")оцінюють true?

Я виконання чисельних операцій на поле введення тексту, і я перевіряю , якщо поле null, ""або NaN. Коли хтось набирає в поле кілька пробілів, у мене триває перевірка на всіх трьох, і я плутаюсь, чому вона проходить isNaNперевірку.


1
Гм ... не зовсім впевнений, куди пішла друга половина теми. Він повинен читати: "JavaScript: Чому isNaN (" ") визначається помилковим?"
Месник IVR

Джес, така поведінка (порожнє або пробіл повертає помилкове значення для isNaN), але я не знайшов точних характеристик цієї функції.
Lucero

Ось питання, яке відповідає на це: http://stackoverflow.com/questions/115548/why-is-isnannull-false-in-js
Lucero

Javascript у цих питаннях здається вуду! Ніколи не знаєш, і пояснення завжди досить складне. "" == false // trueіisNaN(" ") // false
Жоао Піментел Феррейра

Відповіді:


155

JavaScript інтерпретує порожній рядок як 0, що потім не відповідає тесту isNAN. Ви можете використовувати parseInt спочатку в рядку, який не перетворить порожній рядок до 0. Потім результат повинен бути невдалим: NAN.


53
Але parseInt ("123abcd") повертає 123, це означає, що isNaN (parseInt ("123abcd")) поверне помилковим, тоді як він повинен повернути true!
Pawan Nogariya

11
То як щодо (IsNaN (string) || isNaN (parseInt (string)))
мат

5
Є 2 кроки в тлумаченні isNaN(arg). 1) Перетворити аргумент в число, 2) Перевірити, чи є це число числовим значенням NaN. Це допомогло мені зрозуміти це краще.
xdhmoore

3
@Antonio_Haley Почекай, я не розумію. Якщо "JavaScript інтерпретує порожній рядок як 0", чому parseInt ("") повертає NaN?
Жан-Франсуа Бошамп

1
@ Жан-Франсуа Ви маєте рацію, більш правильним буде твердження: "isNaN інтерпретує порожній рядок як 0", а не сам JavaScript.
Антоніо Хейлі

82

Ви можете здати це дивовижним, а може й ні, але ось якийсь тестовий код, який покаже вам хитрість JavaScript-механізму.

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

але

"" != " "

Приємно :)


5
+1 Чудовий пост. Чи можете ви додати, як тут вписується оператор потрійних рівних (=== і! ==)?
bendewey

2
Спробуйте спробувати NaN === NaN або NaN == NaN ;-) Я не знаю, чи все це означає, що двигун javascript нерозумний або що JavaScript поганий для прискіпливих програмістів.
KooiInc

10
@Kooilnc той факт, що NaN! = NaN, насправді, хороший вибір на один раз. Ідея полягає в тому, що NaN майже завжди є результатом обчислень, які йшли інакше, ніж планував програміст, і вважати, що результати двох обчислень, які пішли "неправильно", є досить небезпечними, я б сказав.
skrebbel

2
@Kooilnc не відбирає навіть трохи від нерозумності JavaScript, але ці NaN просто підкоряються стандарту IEEE 754 з плаваючою точкою. Ви можете прочитати ВСЕ про це, як завжди, на великій W: en.wikipedia.org/wiki/NaN
Spike0xff

@NickBerardi F'ing LOL! Я так радий, що побачив цей пост. Допоміг мені зрозуміти, чому функція isNaN настільки відстала. Я зараз зніму його з не повністю розробленого коду, і, ймовірно, більше ніколи його не буду використовувати. Я перевірити для null, ""і " "я сам. Дякую!
VoidKing

16

Щоб краще зрозуміти це, відкрийте Ecma-Script spec pdf на сторінці 43 "ToNumber застосовано до типу рядка"

якщо рядок має числовий синтаксис, який може містити будь-яку кількість символів пробілу, він може бути перетворений у тип номера. Порожній рядок оцінюється до 0. Також рядок "Нескінченність" повинен дати

isNaN('Infinity'); // false

13

Спробуйте скористатися:

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

Або

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

3
привіт, сер, isNaN (parseInt ("123a")): повернеться 123, тому ур-рішення не буде працювати, якщо рядок містить aplha числовий
Sajjad Ali Khan

6

З MDNпричини причини, з якою ви стикаєтесь

Коли аргумент функції isNaN не має типу Number, значення спочатку прирівнюється до числа. Потім отримане значення тестують, щоб визначити, чи це NaN.

Ви можете перевірити наступну вичерпну відповідь, яка охоплює порівняння NaN щодо рівності.

Як перевірити, чи є змінна JavaScript NaN


5

Я думаю, це через типізацію Javascript: ' 'перетворюється на нуль, тоді 'x'як не:

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

4

Якщо ви хочете реалізувати точну функцію isNumber, ось один із способів зробити це з Javascript: хороші частини Дугласа Крокфорда [стор. 105]

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

4
@Xyan, в такому випадку ця функція не дуже допомагає виконувати завдання, яке просив зробити ОП, а саме - перевірити рядкове представлення числа ...
ErikE

використання так званого оператора суворої рівності будь-якого заданого значення проти рядкового літералу, такого як "число", нерозумно,
Бекім Bacaj

4

Не зовсім правильний відповідь

Тут висококваліфікована і прийнята відповідь Антоніо Хейлі робить неправильне припущення, що цей процес проходить через parseIntфункцію JavaScript :

Ви можете використовувати parseInt в рядку ... Результат повинен бути невдалим: NAN.

Ми можемо легко спростувати це твердження рядком "123abc":

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

З цим ми можемо бачити, що parseIntфункція JavaScript повертається "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.


2

Я не впевнений, чому , але, щоб подолати проблему, ви завжди можете обрізати пробіл перед тим, як перевірити. Ви, мабуть, хочете це зробити в будь-якому випадку.


4
обрізана порожня рядок також не відповідає тесту isNaN.
Єгеменк

2

Функція isNaN("")виконує примус типу " Рядок до числа"

ECMAScript 3-5 визначає наступні повернені значення для оператора typeof:

  • невизначений
  • об'єкт (null, object, масиви)
  • булева
  • число
  • рядок
  • функція

Краще завершити наш тест у функції функції:

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")

1

Я пропоную вам скористатися такою функцією, якщо ви дійсно хочете належної перевірки, чи це ціле число:

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

1

Це isNaN(" ")неправда є частиною заплутаної поведінки isNaNглобальної функції через її примушення нечисел до числового типу.

Від MDN :

Починаючи з самих ранніх версій isNaNспецифікації функції, її поведінка для нечислових аргументів є заплутаною. Коли аргумент isNaNфункції не типу Number, значення спочатку прирівнюється до числа. Потім отримане значення тестується для визначення того, чи є воно NaN. Таким чином, для нечисленних цифр, які при примусовому чисельному типі призводять до дійсного числового значення, що не відповідає NaN (зокрема, порожній рядок та булеві примітиви, які при примусовій формі дають числові значення нуль або один), "помилкове" повернене значення може бути несподіваним; Наприклад, порожній рядок, безумовно, "не число".

Зауважимо також, що з ECMAScript 6 також існує Number.isNaNметод, який згідно MDN:

У порівнянні з глобальною isNaN()функцією Number.isNaN()не виникає проблеми насильницького перетворення параметра в число. Це означає, що тепер безпечно передавати значення, які зазвичай перетворюються NaN, але насправді не є тим самим значенням, як NaN. Це також означає, що NaNповертаються лише значення номера типу, які також є true.

На жаль :

Навіть у Number.isNaNметоду ECMAScript 6 є свої проблеми, як викладено у публікації блогу - Виправлення негарної проблеми JavaScript та ES6 NaN .


1

isNaNФункція очікує номер в якості аргументу, тому аргументи будь-якого іншого типу (в вашому випадку рядки) будуть перетворені в номер , перш ніж виконуються фактична функція логіки. (Майте на увазі, що NaNце також значення типу Number!)

Btw. це є загальним для всіх вбудованих функцій - якщо вони очікують аргументу певного типу, фактичний аргумент буде перетворений за допомогою стандартних функцій перетворення. Існують стандартні перетворення між усіма основними типами (bool, рядок, число, об'єкт, дата, null, undefined.)

Стандартне перетворення для 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


1

Я написав цю швидку маленьку функцію, щоб допомогти вирішити цю проблему.

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

Він просто перевіряє наявність будь-яких символів, які не є числовими (0-9), які не є "-" або ".", І які не визначені, нульові або порожні, і повертає справжнє значення, якщо немає відповідностей. :)


Запізніле спасибі за це; це дуже добре вирішило мою проблему.
Генрі

1

Як інше пояснено, isNaNфункція буде примушувати порожню рядок до числа, перш ніж перевірити її, таким чином змінивши порожній рядок на 0 (що є дійсним числом). Однак я виявив, що parseIntфункція повернеться NaNпри спробі розбору порожнього рядка або рядка з лише пробілами. Отже, наступна комбінація, здається, працює добре:

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

Ця перевірка буде працювати для додатних чисел, від’ємних чисел та чисел із десятковою комою, тому я вважаю, що вона охоплює всі загальні числові випадки.


1

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це значення, спершу слід спробувати перетворити його у число.


0

Ця функція, здавалося, працює в моїх тестах

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

2
Всю вашу функцію можна записати:return !(s === "" || s === null || parseInt(s) == 'NaN');
ErikE

0

А як на рахунок

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

0

JavaScript вбудований в IsNaN функції, це - як і слід було очікувати , за замовчуванням - це «Динамічний тип оператора». Тому всі значення, які (під час процесу DTC) можуть дати просту правду | помилкові, такі як"", " ", " 000" , не може бути NaN.

Це означає, що поданий аргумент спочатку зазнає перетворення, як у:

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

Пояснення:

У верхньому рядку функції функції ми (спершу) намагаємось успішно перетворити аргумент в об'єкт числа. І (другий), з допомогою оператора точки ми - для власної зручності - негайно вирізують, примітивне значення створюваного об'єкта.

У другому рядку ми беремо значення, отримані на попередньому кроці, і перевага того, що NaN не дорівнює ні чомусь у Всесвіті, навіть самому собі, наприклад:NaN == NaN >> false нарешті порівняти його (за нерівність) із самим собою .

Таким чином, повернення функції буде істинним лише тоді, коли і лише у тому випадку, якщо наданий аргумент-повернення є невдалою спробою перетворення на об'єкт числа, тобто число, яке не є числом; наприклад, NaN.


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що це (аргумент) - це звичайний рядок.

ps: Статична версія isNaN може бути дуже корисною в сучасних сценаріях кодування. І це, можливо, є однією з головних причин, коли я витратив свій час на публікацію цього питання.

З повагою


0

isNAN(<argument>)- це функція визначати, чи вказаний аргумент є незаконним номером. isNaNвводить аргументи в числовий тип. Якщо ви хочете перевірити, чи аргумент є числовим чи ні? Будь ласка, використовуйте $.isNumeric()функцію в jQuery.

Тобто, isNaN (foo) еквівалентно isNaN (Number (foo)) Він приймає будь-які рядки, що мають усі цифри, як числа з зрозумілих причин. Для екс.

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

0

Я цим користуюся

    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


0

Перевіряючи, чи є певне значення рядка з пробілом або " ", isNaNможливо, спробуйте виконати перевірку рядків, наприклад:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.