Perché isNaN (“”) (stringa con spazi) è uguale a falso?


160

In JavaScript, perché isNaN(" ")valuta false, ma isNaN(" x")valuta true?

Sto eseguendo operazioni numeriche in un campo di testo, e sto controllando se il campo è null, ""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 isNaNcontrollo.


1
Hm ... non sono sicuro di dove sia finita l'altra metà del soggetto. Dovrebbe leggere "JavaScript: perché isNaN (" ") viene valutato come falso?"
IVR Avenger,

Jes, questo è il comportamento (vuoto o spazio restituisce false per isNaN), ma non ho trovato le specifiche esatte di questa funzione.
Lucero,

Ecco una domanda che risponde a questa domanda: http://stackoverflow.com/questions/115548/why-is-isnannull-false-in-js
Lucero

Javascript su questi temi sembra voodoo! Non lo sai mai e la spiegazione è sempre piuttosto complessa. "" == false // trueeisNaN(" ") // false
João Pimentel Ferreira il

Risposte:


155

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


53
Ma parseInt ("123abcd") restituisce 123, il che significa che isNaN (parseInt ("123abcd")) restituirà false mentre dovrebbe restituire true!
Pawan Nogariya,

11
Che ne dici di (IsNaN (stringa) || isNaN (parseInt (stringa)))
matt

5
Ci sono 2 passaggi nell'interpretazione isNaN(arg). 1) Converti arg in numero, 2) Verifica se quel numero è il valore numerico NaN. Questo mi ha aiutato a capirlo meglio.
xdhmoore,

3
@Antonio_Haley Aspetta un minuto, non capisco. Se "JavaScript interpreta una stringa vuota come 0", perché parseInt ("") restituisce NaN?
Jean-François Beauchamp,

1
@ Jean-François Hai ragione, l'affermazione più corretta sarebbe "isNaN interpreta una stringa vuota come 0", non JavaScript stesso.
Antonio Haley,

82

Potresti trovare questo sorprendente o forse no, ma ecco 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 che

" " == 0 == false

e

"" == 0 == false

ma

"" != " "

Divertiti :)


5
+1 Ottimo post. Puoi aggiungere come l'operatore triple uguale (=== e! ==) si adatta qui?
Bendewey,

2
Dovresti provare NaN === NaN o NaN == NaN ;-) Non so se tutto ciò significhi che il motore javascript è stravagante o che javascript è dannoso per i programmatori stravaganti.
KooiInc,

10
@Kooilnc il fatto che NaN! = NaN sia, in realtà, una buona scelta per una volta. L'idea è che NaN sia quasi sempre il risultato di un calcolo che è andato diversamente da come intendeva il programmatore, e supporre che i risultati di due calcoli che sono andati "male" siano uguali è piuttosto pericoloso, direi.
skrebbel,

2
@Kooilnc non toglie nemmeno un po 'dalla stravaganza di JavaScript, ma questi NaN stanno solo obbedendo allo standard IEEE 754 in virgola mobile. Puoi leggere TUTTO come al solito sul grande W: en.wikipedia.org/wiki/NaN
Spike0xff

@NickBerardi F'ing LOL! Sono così felice di aver visto questo post. Mi ha aiutato a capire perché la funzione isNaN è così ritardata. Lo toglierò dal mio codice non completamente sviluppato in questo momento e probabilmente non lo userò mai più. Io validare per null, ""e " "me stesso. Grazie!
VoidKing,

16

Per capirlo meglio, apri il pdf delle specifiche Ecma-Script 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 nel tipo di numero. La stringa vuota ha valore 0. Anche la stringa 'Infinity' dovrebbe dare

isNaN('Infinity'); // false

13

Prova a usare:

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

O

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

3
ciao signore, isNaN (parseInt ("123a")): restituirà 123 quindi la tua soluzione non funzionerà, se la stringa contiene aplha numerico
Sajjad Ali Khan

6

Dalla MDNragione del problema che stai affrontando

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.

Come verificare se una variabile JavaScript è NaN


5

Penso che sia a causa della digitazione di Javascript: ' 'viene convertito in zero, mentre 'x'non lo è:

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

4

Se desideri implementare un'accurata funzione isNumber, 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);
}

4
@Xyan nel qual caso questa funzione non è molto utile per eseguire l'attività che l'OP stava chiedendo di fare, che era di ispezionare una rappresentazione in stringa di un numero ...
ErikE

usare il cosiddetto operatore di uguaglianza rigorosa di un dato valore contro una stringa letterale come "numero" è stupido,
Bekim Bacaj

4

La risposta non del tutto corretta

La risposta molto apprezzata e accettata di Antonio Haley qui fa un'errata supposizione che questo processo passi attraverso la parseIntfunzione JavaScript :

È possibile 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 parseIntfunzione JavaScript ritorna "123abc"come numero 123, ma la sua isNaNfunzione ci dice che "123abc" non lo è un numero.

La risposta corretta

ECMAScript-262 definisce come funziona il isNaNcontrollo nella sezione 18.2.3 .

18.2.3 isNaN(Numero)

La isNaNfunzione è l' %isNaN%oggetto intrinseco. Quando la isNaNfunzione viene chiamata con un numero di argomento, vengono eseguite le seguenti operazioni:

  1. Lascia numstare? ToNumber(number).
  2. Se numè NaN, ritorna true.
  3. Altrimenti, ritorna false.

La ToNumberfunzione a cui fa riferimento è anche definita 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 contenente nient'altro che caratteri di spazi bianchi. Questa sezione afferma che:

Viene StringNumericLiteralconvertito un oggetto vuoto o che contiene solo spazi bianchi +0.

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

La stessa sezione afferma inoltre:

Se la grammatica non può interpretare Stringcome un'espansione di StringNumericLiteral, allora il risultato di ToNumberè NaN.

Senza citare tutti i controlli contenuti in quella sezione, l' " x"esempio fornito nella domanda rientra nelle condizioni sopra riportate in quanto non può essere interpretato come a StringNumericLiteral. " x"viene quindi convertito in NaN.


2

Non sono sicuro del perché , ma per aggirare il problema è sempre possibile tagliare gli spazi bianchi prima di controllare. Probabilmente vorrai farlo comunque.


4
anche una stringa vuota tagliata non riesce isNaN test.
Egemenk,

2

La funzione isNaN("")esegue una coercizione da stringa a numero

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

  • non definito
  • oggetto (null, oggetti, matrici)
  • booleano
  • numero
  • corda
  • funzione

Meglio avvolgere il nostro test in un corpo funzionale:

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 il tipo di variabile , ma verifica il valore forzato . Ad esempio, i booleani e le stringhe sono costretti a numeri, quindi forse potresti voler chiamare questa funzione comeisNumberCoerced()

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

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

1

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);
}

1

Ciò isNaN(" ")è falso fa parte del comportamento confuso della isNaNfunzione globale a causa della sua coercizione di non numeri a un tipo numerico.

Da MDN :

Fin dalle prime versioni della isNaNspecifica della funzione, il suo comportamento per argomenti non numerici è stato confuso. Quando l'argomento della isNaNfunzione non è di tipo Numero, il valore viene prima forzato in un numero. Il valore risultante viene quindi testato per determinare se lo è 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 valore restituito "falso" potrebbe essere inatteso; la stringa vuota, ad esempio, è sicuramente "non un numero".

Si noti inoltre che con ECMAScript 6, ora esiste anche il Number.isNaNmetodo, che secondo MDN:

Rispetto alla isNaN()funzione globale , Number.isNaN()non presenta il problema di convertire forzatamente il parametro in un numero. Ciò significa che ora è sicuro passare valori che normalmente verrebbero convertiti NaN, ma in realtà non sono lo stesso valore di NaN. Questo significa anche che NaNrestituiscono solo i valori del numero di tipo, che sono anch'essi true.

Sfortunatamente :

Anche il Number.isNaNmetodo ECMAScript 6 ha i suoi problemi, come indicato nel post del blog - Risolto il brutto problema di JavaScript e NaN ES6 .


1

La isNaNfunzione prevede 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. (Tenere presente che NaNè anche un valore di tipo Numero!)

Btw. questo è comune per tutte le funzioni integrate: se si aspettano un argomento di un certo tipo, l'argomento effettivo verrà convertito utilizzando 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 Stringto Numberpuò essere invocata esplicitamente con Number(). Quindi possiamo vedere che:

  • Number(" ") valuta 0
  • Number(" x") valuta NaN

Detto questo, il risultato della isNaNfunzione è 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" in 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


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. :)


Un tardivo grazie per questo; questo ha risolto il mio problema molto bene.
Henry,

1

Come altri hanno spiegato, la isNaNfunzione costringe 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 parseIntfunzione tornerà NaNquando 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à per numeri positivi, numeri negativi e numeri con un punto decimale, quindi credo che copra tutti i casi numerici comuni.


1

NaN ! == "not a number"

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.


0

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;
        }
    }
}

2
L'intera funzione può essere scritta:return !(s === "" || s === null || parseInt(s) == 'NaN');
ErikE

0

Che dire

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

0

La funzione isNaN integrata di JavaScript è, 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 | falso come"", " ", " 000" , non può essere NaN.

Ciò significa che l' argomento fornito verrà prima sottoposto a 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 rimuovere 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;
}

Ed 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"); // will return false perché è ancora una stringa.

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

Ma al contrario isNaN, il isNaNStatic("NaN"); >> falseperché esso (l'argomento) è una stringa ordinaria.

ps: 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 per pubblicarlo.

Saluti.


0

isNAN(<argument>)è una funzione per dire se un determinato argomento è un numero illegale. isNaNdattiloscrive gli argomenti in Tipo numero. Se vuoi verificare se l'argomento è Numerico o no? Si prega di utilizzare la $.isNumeric()funzione in jQuery.

Cioè, isNaN (foo) è equivalente a isNaN (Number (foo)) Accetta qualsiasi stringa con 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

0

Io lo uso

    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

Quando si controlla se un determinato valore di stringa con spazi bianchi o " "è isNaNforse provare a eseguire la convalida della stringa, ad esempio:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.