Perché isNaN (“”) è uguale a false

Ho una domanda veloce (spero!). In JS, perché isNaN(" ") valuta su false, ma isNaN(" x") valuta su true?

Sto eseguendo operazioni numeriche su un campo di inserimento testo e sto verificando se il campo è nullo, “” o NaN. Quando qualcuno digita una manciata di spazi nel campo, la mia validazione fallisce su tutti e tre, e sono confuso sul motivo per cui supera il controllo isNAN.

Grazie!

JavaScript interpreta una stringa vuota come 0, quindi fallisce il test isNAN. È ansible utilizzare prima parseInt sulla stringa che non converte la stringa vuota in 0. Il risultato dovrebbe quindi fallire isNAN.

Potresti trovarlo sorprendente o forse no, ma qui c’è un codice di prova per mostrarti la stranezza del motore 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 

quindi questo significa

 " " == 0 == false 

e

 "" == 0 == false 

ma

 "" != " " 

Divertiti 🙂

Prova a usare:

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

O

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

Per capirlo meglio, apri il pdf di Ecma-Script spec a pagina 43 “ToNumber Applicato al tipo di stringa”

se una stringa ha una syntax numerica, che può contenere un numero qualsiasi di caratteri spazi bianchi, può essere convertita in tipo Numero. La stringa vuota viene valutata a 0. Anche la stringa ‘Infinity’ dovrebbe dare

 isNaN('Infinity'); // false 

Dalla ragione MDN per il problema che stai affrontando

Quando l’argomento della funzione isNaN non è di tipo Number, il valore viene prima convertito in un numero. Il valore risultante viene quindi testato per determinare se si tratta di NaN.

Potresti voler controllare la seguente risposta esauriente che copre anche il confronto NaN per l’uguaglianza.

Come verificare se una variabile JavaScript è NaN

Penso che sia dovuto alla digitazione di Javascript: ' ' è convertito a zero, mentre 'x' non lo è:

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

Se vuoi implementare una funzione isNumber accurata, ecco un modo per farlo da Javascript: The Good Parts di Douglas Crockford [pagina 105]

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

La risposta non completamente corretta

La risposta altamente affermata e accettata di Antonio Haley fa qui un’assunzione errata che questo processo passi attraverso la funzione parseInt di JavaScript:

È ansible utilizzare parseInt sulla stringa … Il risultato dovrebbe quindi fallire isNAN.

Possiamo facilmente confutare questa affermazione con la stringa "123abc" :

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

Con questo, possiamo vedere che la funzione parseInt di JavaScript restituisce "123abc" come numero 123 , tuttavia la sua funzione isNaN ci dice che "123abc" non è un numero.

La risposta corretta

ECMAScript-262 definisce come funziona il controllo isNaN nella sezione 18.2.3 .

18.2.3 isNaN (numero)

La funzione isNaN è l’object intrinseco %isNaN% . Quando la funzione isNaN viene chiamata con un numero argomento, vengono isNaN i seguenti passaggi:

  1. Sia num ? ToNumber(number) .
  2. Se num è NaN , restituisce true .
  3. Altrimenti, restituisci false .

La funzione ToNumber a cui fa riferimento è definita anche nella sezione 7.1.3 di ECMAScript-262 . Qui, ci viene detto come JavaScript gestisce le stringhe che vengono passate a questa funzione.

Il primo esempio fornito nella domanda è una stringa che contiene nient’altro che caratteri di spazio bianco. Questa sezione afferma che:

Un object StringNumericLiteral vuoto o che contiene solo spazi bianchi viene convertito in +0 .

La stringa di esempio " " viene quindi convertita in +0 , che è un numero.

La stessa sezione afferma inoltre:

Se la grammatica non può interpretare la String come un’espansione di StringNumericLiteral , il risultato di ToNumber è NaN .

Senza citare tutti i controlli contenuti all’interno di quella sezione, l’esempio " x" fornito nella domanda rientra nella condizione precedente in quanto non può essere interpretato come StringNumericLiteral . " x" viene quindi convertito in NaN .

Non sono sicuro del perché , ma per aggirare il problema potresti sempre ridurre gli spazi bianchi prima di controllare. Probabilmente vorresti farlo comunque.

La funzione isNaN("") esegue una coercizione di tipo String to Number

ECMAScript 3-5 definisce i seguenti valori di ritorno per l’operatore typeof:

  • non definito
  • object (null, oggetti, matrici)
  • booleano
  • numero
  • stringa
  • funzione

Meglio avvolgere il nostro test in un corpo di una funzione:

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

Questa funzione non ha l’intento di testare il tipo di variabile, ma verifica il valore forzato . Ad esempio, booleani e stringhe sono costretti a numeri, quindi forse potresti voler chiamare questa funzione come isNumberCoerced()

se non è necessario testare tipi diversi da stringa e numero , il seguente frammento potrebbe essere utilizzato come parte di una condizione:

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

Ti suggerisco di usare la seguente funzione se vuoi veramente un controllo corretto se è un numero intero:

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

That isNaN(" ") is false è parte del comportamento confuso della funzione globale isNaN causa della coercizione di non numeri a un tipo numerico.

Da MDN :

Fin dalle primissime versioni della specifica della funzione isNaN , il suo comportamento per gli argomenti non numerici è stato confuso. Quando l’argomento della funzione isNaN non è di tipo Number, il valore viene prima convertito in un numero. Il valore risultante viene quindi testato per determinare se si tratta di NaN . Quindi per numeri non numerici che quando costretti al tipo numerico danno come risultato un valore numerico non NaN valido (in particolare la stringa vuota e le primitive booleane, che quando costruite danno valori numerici zero o uno), il valore restituito “falso” potrebbe essere inaspettato; la stringa vuota, ad esempio, è sicuramente “non un numero”.

Si noti inoltre che con ECMAScript 6 è ora disponibile anche il metodo Number.isNaN , che secondo MDN:

In confronto alla funzione globale isNaN() , Number.isNaN() non ha il problema di convertire forzatamente il parametro in un numero. Ciò significa che ora è sicuro passare valori che normalmente sarebbero convertiti in NaN , ma in realtà non hanno lo stesso valore di NaN . Ciò significa anche che solo i valori del numero di tipo, che sono anche NaN , restituiscono true .

Purtroppo :

Anche il metodo Number.isNaN ECMAScript 6 ha i suoi problemi, come delineato nel post del blog – Correggere il brutto problema con JavaScript e ES6 NaN .

Come altri ha spiegato la funzione isNaN costringerà la stringa vuota in un numero prima di convalidarlo, modificando così una stringa vuota in 0 (che è un numero valido). Tuttavia, ho trovato che la funzione parseInt restituirà NaN quando si tenta di analizzare una stringa vuota o una stringa con solo spazi. Come tale, la seguente combinazione sembra funzionare bene:

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

Questo controllo funzionerà con numeri positivi, numeri negativi e numeri con un punto decimale, quindi credo che copra tutti i casi numerici comuni.

Questa funzione sembrava funzionare nei miei test

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

Che dire

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

La funzione isNaN aspetta un numero come argomento, quindi gli argomenti di qualsiasi altro tipo (nel tuo caso una stringa) verranno convertiti in numero prima che venga eseguita la logica della funzione effettiva. ( NaN che NaN è anche un valore di tipo Numero!)

Btw. questo è comune a tutte le funzioni built-in – se si aspettano un argomento di un certo tipo, l’argomento attuale verrà convertito usando le funzioni di conversione standard. Esistono conversioni standard tra tutti i tipi di base (bool, stringa, numero, object, data, null, indefinito).

La conversione standard per String su Number può essere invocata esplicitamente con Number() . Quindi possiamo vedere che:

  • Number(" ") valutato a 0
  • Number(" x") valutato in NaN

Detto questo, il risultato della funzione isNaN è completamente logico!

La vera domanda è perché la conversione standard da stringa a numero funziona come fa. La conversione da stringa a numero è pensata per convertire stringhe numeriche come “123” o “17.5e4” in numeri equivalenti. La conversione prima salta lo spazio bianco iniziale (quindi “123” è valido) e quindi tenta di analizzare i resti come un numero. Se non è analizzabile come numero (“x” non lo è), il risultato è NaN. Ma esiste la regola speciale esplicita che una stringa che è vuota o solo lo spazio bianco è convertita in 0. Quindi questo spiega la conversione.

Riferimento: http://www.ecma-international.org/ecma-262/5.1/#sec-9.3.1

Ho scritto questa rapida piccola funzione per aiutare a risolvere questo problema.

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

Controlla semplicemente i caratteri non numerici (0-9), che non sono ‘-‘ o ‘.’, E che non sono indefiniti, nulli o vuoti e restituiscono true se non ci sono corrispondenze. 🙂

La funzione isNaN incorporata di JavaScript è, come dovrebbe essere previsto per impostazione predefinita, un “Operatore di tipo dinamico”. Quindi tutti i valori che (durante il processo DTC) possono produrre un semplice vero | false come "", " ", " 000" , non possono essere NaN.

Significa che l’ argomento fornito subirà prima una conversione come in:

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

Spiegazione:

Nella riga superiore del corpo della funzione, stiamo (prima) cercando di convertire correttamente l’argomento in un numero object. E (secondo), usando l’operatore punto siamo – per la nostra convenienza – immediatamente estraendo, il valore primitivo dell’object creato.

Nella seconda riga, stiamo prendendo il valore ottenuto nel passaggio precedente e il vantaggio del fatto che NaN non è uguale a nulla nell’universo, nemmeno a se stesso, ad esempio: NaN == NaN >> false per confrontare infine (per disuguaglianza) con se stesso.

In questo modo la funzione return restituirà true solo quando, e solo se, l’argomento-return fornito, è un tentativo fallito di conversione in un numero object, cioè un numero non numerico; ad esempio, NaN.


isNaNstatic ()

Tuttavia, per un operatore di tipo statico – se necessario e quando necessario – possiamo scrivere una funzione molto più semplice come:

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

Ed evita completamente il DTC in modo tale che se l’argomento non è esplicitamente un numero NaN, restituirà false. Pertanto, testare contro quanto segue:

isNaNStatic(" x"); // will return false isNaNStatic(" x"); // will return false perché è ancora una stringa.

Tuttavia: isNaNStatic(1/"x"); // will of course return true. isNaNStatic(1/"x"); // will of course return true. come per esempio isNaNStatic(NaN); >> true isNaNStatic(NaN); >> true .

Ma contrariamente a isNaN , isNaNStatic("NaN"); >> false isNaNStatic("NaN"); >> false perché (l’argomento) è una stringa ordinaria.

ps: la versione statica di isNaN può essere molto utile negli scenari di codifica moderni. E potrebbe benissimo essere uno dei motivi principali per cui mi sono preso il tempo per postarlo.

Saluti.

isNAN() è una funzione che indica se l’argomento dato è un numero non isNAN() . isNaN tipizza gli argomenti in Tipo numero. Se vuoi controllare se l’argomento è numerico o no? Utilizzare la funzione $.isNumeric() in jQuery.

Cioè, isNaN (foo) è equivalente a isNaN (Number (foo)) Accetta qualsiasi stringa che abbia tutti i numeri come numeri per ovvi motivi. Per es.

 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 

Io uso questo

  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 ! == “non un numero”

NaN è un valore di Number Type

questa è una definizione di isNaN () in ECMAScript

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

Prova a convertire qualsiasi valore in Numero.

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

Se si desidera determinare se il valore è NaN , provare prima a convertirlo in un valore Numero.

Quando si verifica se un determinato valore di stringa con spazio bianco o " " è isNaN provare a eseguire la verifica stringa, ad esempio:

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