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!

È stato utile?

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

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 funzione:

  

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 funzione isNaN viene chiamata con un numero argomento, vengono prese le seguenti fasi:

     
      
  1. Sia num essere? ToNumber (numero) .
  2.   
  3. Se num è NaN , restituisce true .
  4.   
  5. Altrimenti, restituisce false .
  6.   

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 di StringNumericLiteral , il risultato di ToNumber è 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
  • 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 funzione isNaN 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 in NaN , ma in realtà non sono 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 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 (" ") restituisce 0
  • Numero (" x ") restituisce NaN

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 }

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top