Perché isNaN (“”) equivale a falso
-
05-07-2019 - |
Domanda
Ho una domanda veloce (spero!). In JS, perché isNaN (" ")
valuta falso, ma isNaN (" x ")
valuta vero?
Sto eseguendo operazioni numeriche su un campo di input di testo e sto verificando se il campo è null, "quot", o NaN. Quando qualcuno digita una manciata di spazi nel campo, la mia convalida fallisce su tutti e tre e sono confuso sul perché supera il controllo isNAN.
Grazie!
Soluzione
JavaScript interpreta una stringa vuota come 0, che quindi non supera il test isNAN. Puoi usare prima parseInt sulla stringa che non converte la stringa vuota in 0. Il risultato dovrebbe fallire isNAN.
Altri suggerimenti
Potresti trovare questo sorprendente o forse no, ma ecco un po 'di 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 che
" " == 0 == false
e
"" == 0 == false
ma
"" != " "
Buon divertimento :)
Per capirlo meglio, apri Specifiche Ecma-Script pdf a pagina 43 " ToNumber applicato al tipo di stringa "
se una stringa ha una sintassi numerica, che può contenere qualsiasi numero di caratteri di spazi bianchi, può essere convertita in tipo Numero. La stringa vuota restituisce 0. Anche la stringa 'Infinity' dovrebbe dare
isNaN('Infinity'); // false
Prova a usare:
alert(isNaN(parseInt(" ")));
o
alert(isNaN(parseFloat(" ")));
Da MDN
motivo del problema riscontrato
Quando l'argomento della funzione isNaN non è di tipo Numero, il valore viene prima forzato in un numero. Il valore risultante viene quindi testato per determinare se è NaN.
Potresti voler controllare la seguente risposta completa che copre anche il confronto NaN per l'uguaglianza.
Penso che sia a causa della digitazione di Javascript: ''
viene convertito in zero, mentre 'x'
non è:
alert(' ' * 1); // 0
alert('x' * 1); // NaN
Se desideri implementare un'accurata funzione isNumber, ecco un modo per farlo da Javascript: le parti buone di Douglas Crockford [pagina 105]
var isNumber = function isNumber(value) {
return typeof value === 'number' &&
isFinite(value);
}
La risposta non interamente corretta
La risposta altamente accettata e accettata di Antonio Haley qui presuppone erroneamente che questo processo passi attraverso parseInt
Puoi usare parseInt sulla stringa ... Il risultato dovrebbe 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 il numero 123
, ma il suo èNN
ci dice che " 123abc "
non è un numero.
La risposta corretta
ECMAScript-262 definisce il funzionamento del controllo isNaN
in sezione 18.2.3 .
18.2.3
isNaN
(Numero)La funzione
isNaN
è l'oggetto intrinseco% isNaN%
. Quando la funzioneisNaN
viene chiamata con un numero argomento, vengono prese le seguenti fasi:
- Sia
num
essere?ToNumber (numero)
.- Se
num
èNaN
, restituiscetrue
.- Altrimenti, restituisce
false
.
La funzione ToNumber
a cui fa riferimento è anche definita in ECMAScript- 262's sezione 7.1.3 . Qui, ci viene detto come JavaScript gestisce le stringhe che vengono passate a questa funzione.
Il primo esempio fornito nella domanda è una stringa contenente nient'altro che caratteri di spazi bianchi. Questa sezione afferma che:
Un
StringNumericLiteral
che è vuoto o che contiene solo spazi bianchi viene convertito in+0
.
Il " "
la stringa di esempio viene quindi convertita in +0
, che è un numero.
La stessa sezione indica anche:
Se la grammatica non è in grado di interpretare
String
come un'espansione diStringNumericLiteral
, il risultato diToNumber
èNaN
.
Senza citare tutti i controlli contenuti in quella sezione, il " 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 perché , ma per aggirare il problema potresti sempre tagliare gli spazi bianchi prima di controllare. Probabilmente vuoi farlo comunque.
La funzione isNaN (" ")
esegue una stringa al numero coercizione di tipo
ECMAScript 3-5 definisce i seguenti valori di ritorno per il operatore typeof:
- non definita ??li>
- oggetto (null, oggetti, matrici)
- booleano
- Numero
- stringa
- Funzione
Meglio avvolgere il nostro test in un corpo di 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 lo scopo di testare la variabile tipo , ma verifica il valore forzato . Ad esempio, i booleani e le stringhe sono obbligati ai 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 alcune condizioni :
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 davvero un controllo corretto se è un numero intero:
function isInteger(s)
{
return Math.ceil(s) == Math.floor(s);
}
Che isNaN (" ")
è falso fa parte del comportamento confuso della funzione globale isNaN
a causa della sua coercizione di non numeri a un tipo numerico .
Da MDN :
Fin dalle primissime versioni della specifica della funzione
isNaN
, il suo comportamento per argomenti non numerici è stato confuso. Quando l'argomento della funzioneisNaN
non è del tipo Numero, il valore viene prima forzato in un numero. Il valore risultante viene quindi testato per determinare se èNaN
. Pertanto, per i non-numeri che, se costretti al tipo numerico, producono un valore numerico non NaN valido (in particolare la stringa vuota e le primitive booleane, che quando costretti danno valori numerici pari a zero o uno), il "falso" il valore restituito potrebbe essere imprevisto; la stringa vuota, ad esempio, non è sicuramente " non un numero. "
Nota anche che con ECMAScript 6, ora esiste anche il metodo Number.isNaN
, che secondo MDN:
Rispetto alla funzione globale
isNaN ()
,Number.isNaN ()
non presenta il problema della conversione forzata del parametro in un numero. Ciò significa che ora è sicuro passare valori che normalmente verrebbero convertiti inNaN
, ma in realtà non sono lo stesso valore diNaN
. Ciò significa anche che solo i valori del numero di tipo, che sono ancheNaN
, restituisconotrue
.
Purtroppo :
Anche il metodo ECMAScript 6 Number.isNaN
ha i suoi problemi, come indicato nel post del blog - Risolto il brutto problema di JavaScript e NaN ES6 .
Come altri hanno spiegato, la funzione isNaN
forzerà la stringa vuota in un numero prima di convalidarla, cambiando così una stringa vuota in 0 (che è un numero valido).
Tuttavia, ho scoperto che la funzione parseInt
restituirà NaN
quando si tenta di analizzare una stringa vuota o una stringa con solo spazi. Pertanto, la seguente combinazione sembra funzionare bene:
if (isNaN (string) || isNaN (parseInt (string))) console.log ('Not a number!');
Questo controllo funzionerà per 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 di
function isNumberRegex(value) {
var pattern = /^[-+]?\d*\.?\d*$/i;
var match = value.match(pattern);
return value.length > 0 && match != null;
}
La funzione isNaN
prevede un numero come argomento, quindi argomenti di qualsiasi altro tipo (nel tuo caso una stringa) verranno convertiti in numero prima della logica della funzione effettiva viene eseguita. (Ricorda che NaN
è anche un valore di tipo Numero!)
Btw. questo è comune per le funzioni incorporate tutte - se si aspettano un argomento di un certo tipo, l'argomento reale verrà convertito usando le funzioni di conversione standard. Esistono conversioni standard tra tutti i tipi di base (bool, stringa, numero, oggetto, data, null, non definito.)
La conversione standard per String
in Number
può essere invocata in modo esplicito con Number ()
. Quindi possiamo vedere che:
-
Numero (" ")
restituisce0
-
Numero (" x ")
restituisceNaN
Detto questo, il risultato della funzione isNaN
è completamente logico!
La vera domanda è: perché la conversione da stringa a numero standard funziona così. La conversione da stringa a numero ha davvero lo scopo di convertire stringhe numeriche come "123". o "17.5e4" ai numeri equivalenti. La conversione salta dapprima lo spazio bianco iniziale (quindi "123" è valido) e quindi tenta di analizzare le pause come numero. Se non è analizzabile come numero (" x " non lo è), il risultato è NaN. Ma c'è la regola speciale esplicita che una stringa vuota o solo bianca viene 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 piccola funzione rapida 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 che non sono numerici (0-9), che non sono '-' o '.' e che non sono indefiniti, nulli o vuoti e restituisce vero se non ci sono corrispondenze. :)
La funzione JavaScript isNaN integrata è, come dovrebbe essere previsto per impostazione predefinita, un operatore di tipo dinamico " ;.
Pertanto tutti i valori che (durante il processo DTC) possono produrre un semplice vero | false come " " ;, " " ;, " 000 "
, non può essere NaN.
Significa che il argomento fornito per prima cosa subirà 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 (innanzitutto) cercando di convertire correttamente l'argomento in un oggetto numerico. E (secondo), usando l'operatore punto siamo - per nostra comodità - a togliere immediatamente il valore primitivo dell'oggetto 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 confrontarlo finalmente (per disuguaglianza) con se stesso.
In questo modo la funzione return restituirà true solo quando, e solo se, l'argomento return-return fornito è un tentativo fallito di conversione in un oggetto numerico, cioè , un numero non numerico; ad es. 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;
}
Evita del tutto il DTC in modo che se l'argomento non è esplicitamente un numero NaN, restituirà false. Pertanto, test per quanto segue:
isNaNStatic (" x "); // restituirà false
perché è ancora una stringa.
Tuttavia:
isNaNStatic (1 / " x "); // ovviamente restituirà true.
come ad esempio isNaNStatic (NaN); & Gt; > true
.
Ma contrariamente a isNaN
, isNaNStatic (" NaN "); & Gt; > false
perché (l'argomento) è una stringa normale.
P.S .: La versione statica di isNaN può essere molto utile nei moderni scenari di codifica. E potrebbe benissimo essere uno dei motivi principali per cui mi sono preso il tempo di pubblicarlo.
Saluti.
isNAN (< argomento >)
è una funzione per dire se un determinato argomento è un numero illegale.
isNaN
digita gli argomenti nel tipo Numero. Se vuoi verificare se l'argomento è numerico o no? Utilizzare la funzione $ .isNumeric ()
in jQuery.
Cioè, isNaN (foo) è equivalente a isNaN (Number (foo)) Accetta qualsiasi stringa con tutti i numeri come numeri per ovvi motivi. Ad esempio.
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
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 Tipo numero
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 vuoi determinare se il valore è NaN
, dovresti prima provare a convertirlo in un valore numerico.
Quando si verifica se un determinato valore di stringa con spazi bianchi o " "
è isNaN
forse prova a eseguire la convalida della stringa, ad esempio:
// value = " 123 "
if (value.match (/ \ s /) || isNaN (value)) {
// fare qualcosa
}