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 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.
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 funzioneisNaN
viene chiamata con un numero argomento, vengonoisNaN
i seguenti passaggi:
- Sia
num
?ToNumber(number)
.- Se
num
èNaN
, restituiscetrue
.- 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 diStringNumericLiteral
, il risultato diToNumber
è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:
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 funzioneisNaN
non è di tipo Number, il valore viene prima convertito in un numero. Il valore risultante viene quindi testato per determinare se si tratta diNaN
. 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 inNaN
, ma in realtà non hanno lo stesso valore diNaN
. Ciò significa anche che solo i valori del numero di tipo, che sono ancheNaN
, restituisconotrue
.
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 }