Pregunta

Tengo una pregunta rápida (¡espero!). En JS, ¿por qué isNaN (" ") se evalúa como falso, pero isNaN (" x ") se evalúa como verdadero?

Estoy realizando operaciones numéricas en un campo de entrada de texto y estoy comprobando si el campo es nulo, " " ;, o NaN. Cuando alguien escribe un puñado de espacios en el campo, mi validación falla en los tres, y estoy confundido en cuanto a por qué se pasa la verificación de ISN.

¡Gracias!

¿Fue útil?

Solución

JavaScript interpreta una cadena vacía como un 0, que luego falla la prueba isNAN. Puede usar parseInt en la cadena primero que no convertirá la cadena vacía a 0. El resultado debería fallar isNAN.

Otros consejos

Puede encontrar esto sorprendente o tal vez no, pero aquí hay un código de prueba para mostrarle la locura del motor de 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

así que esto significa que

" " == 0 == false

y

"" == 0 == false

pero

"" != " "

Diviértete :)

Para comprenderlo mejor, abra Ecma-Script spec pdf en la página 43 " ToNumber aplicado al tipo de cadena "

si una cadena tiene una sintaxis numérica, que puede contener cualquier número de caracteres de espacio en blanco, se puede convertir a Tipo de número. La cadena vacía se evalúa a 0. También la cadena 'Infinito' debería dar

isNaN('Infinity'); // false

Intenta usar:

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

O

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

De MDN razón del problema que enfrenta

  

Cuando el argumento de la función isNaN no es del tipo Número, el valor se convierte primero en un Número. El valor resultante se prueba para determinar si es NaN.

Es posible que desee verificar la siguiente respuesta integral que cubre la comparación NaN para la igualdad también.

  

Cómo probar si una variable de JavaScript es NaN

Creo que se debe a la escritura de Javascript: '' se convierte a cero, mientras que 'x' no es:

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

Si desea implementar una función isNumber precisa, esta es una forma de hacerlo desde Javascript: The Good Parts por Douglas Crockford [página 105]

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

La respuesta no totalmente correcta

respuesta altamente aceptada y aceptada aquí hace una suposición errónea de que este proceso pasa por el código de JavaScript function:

  

Puedes usar parseInt en la cadena ... El resultado debería fallar isNAN.

Podemos refutar fácilmente esta declaración con la cadena " 123abc " :

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

Con esto, podemos ver que la función parseInt de JavaScript devuelve " 123abc " como el número 123 , sin embargo, su esNaN La función nos dice que " 123abc " no es un número.

La respuesta correcta

ECMAScript-262 define cómo funciona la verificación isNaN en sección 18.2.3 .

  

18.2.3 isNaN (Número)

     

La función isNaN es el objeto intrínseco % isNaN% . Cuando se llama a la función isNaN con un número de argumento, se toman los siguientes pasos:

     
      
  1. Sea num ? ToNumber (número) .
  2.   
  3. Si num es NaN , devuelve true .
  4.   
  5. De lo contrario, devuelve false .
  6.   

La función ToNumber a la que hace referencia también se define en ECMAScript- 262's sección 7.1.3 . Aquí, nos dicen cómo JavaScript maneja las cadenas que se pasan a esta función.

El primer ejemplo dado en la pregunta es una cadena que solo contiene caracteres de espacio en blanco. Esta sección establece que:

  

Un StringNumericLiteral que está vacío o que solo contiene espacios en blanco se convierte a +0 .

El " " la cadena de ejemplo se convierte a +0 , que es un número.

La misma sección también dice:

  

Si la gramática no puede interpretar String como una expansión de StringNumericLiteral , el resultado de ToNumber es NaN .

Sin citar todos los controles incluidos en esa sección, el " El ejemplo de x " dado en la pregunta cae en la condición anterior, ya que no se puede interpretar como un StringNumericLiteral . " x " se convierte a NaN .

No estoy seguro de por qué , pero para solucionar el problema, siempre puede recortar los espacios en blanco antes de realizar la comprobación. Probablemente quieras hacer eso de todos modos.

La función isNaN (" ") realiza una Cadena a Número coerción de tipo

ECMAScript 3-5 define los siguientes valores de retorno para el Tipo de operador:

  • indefinido
  • objeto (nulo, objetos, matrices)
  • booleano
  • número
  • cadena
  • función

Mejor envolver nuestra prueba en un cuerpo de función:

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

Esta función no tiene la intención de probar la variable tipo , sino que prueba el valor coaccionado . Por ejemplo, los booleanos y las cadenas se convierten en números, por lo que quizás desee llamar a esta función como isNumberCoerced()

si no hay necesidad de probar tipos que no sean cadena y número , entonces el siguiente fragmento podría usarse como parte de alguna condición :

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

Le sugiero que use la siguiente función si realmente desea una verificación adecuada si es un número entero:

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

Que isNaN (" " ") es falso es parte del comportamiento confuso de la función global isNaN debido a su coacción de no números a un tipo numérico .

De MDN :

  

Desde las primeras versiones de la especificación de la función isNaN , su comportamiento para los argumentos no numéricos ha sido confuso. Cuando el argumento de la función isNaN no es de tipo Number, el valor se convierte primero en un Number. El valor resultante se prueba para determinar si es NaN . Por lo tanto, para los no números que, cuando se los obliga a obtener un tipo numérico, se obtiene un valor numérico no NaN válido (en particular, la cadena vacía y los primitivos booleanos, que cuando son obligados dan valores numéricos de cero o uno), el " falso " el valor devuelto puede ser inesperado; la cadena vacía, por ejemplo, seguramente no es un número. "

También tenga en cuenta que con ECMAScript 6, ahora también existe el método Number.isNaN , que según MDN:

  

En comparación con la función global isNaN () , Number.isNaN () no tiene el problema de convertir a la fuerza el parámetro en un número. Esto significa que ahora es seguro pasar valores que normalmente se convertirían a NaN , pero en realidad no tienen el mismo valor que NaN . Esto también significa que solo los valores del número de tipo, que también son NaN , devuelven true .

Desafortunadamente :

Incluso el método Number.isNaN de ECMAScript 6 tiene sus propios problemas, como se describe en la publicación del blog - Solución del problema feo de JavaScript y ES6 NaN .

Como se explicó anteriormente, la función isNaN coaccionará la cadena vacía a un número antes de validarla, cambiando así una cadena vacía a 0 (que es un número válido). Sin embargo, descubrí que la función parseInt devolverá NaN cuando intente analizar una cadena vacía o una cadena con solo espacios. Como tal, la siguiente combinación parece estar funcionando bien:

if (isNaN (string) || isNaN (parseInt (string))) console.log ('¡No es un número!');

Esta verificación funcionará para números positivos, números negativos y números con un punto decimal, por lo que creo que cubre todos los casos numéricos comunes.

Esta función parecía funcionar en mis pruebas

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

¿Qué pasa con

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

La función isNaN espera un Número como argumento, por lo que los argumentos de cualquier otro tipo (en su caso, una cadena) se convertirán en Número antes de la lógica de la función real es interpretado. (¡Tenga en cuenta que NaN también es un valor de tipo Número!)

Por cierto. esto es común para todas funciones incorporadas: si esperan un argumento de cierto tipo, el argumento real se convertirá usando las funciones de conversión estándar. Hay conversiones estándar entre todos los tipos básicos (bool, string, number, object, date, null, undefined).

La conversión estándar de String a Number se puede invocar explícitamente con Number () . Entonces podemos ver eso:

  • Number (" ") se evalúa como 0
  • El número (" x ") se evalúa como NaN

Dado esto, ¡el resultado de la función isNaN es completamente lógico!

La verdadera pregunta es por qué la conversión estándar de Cadena a Número funciona como lo hace. La conversión de cadena a número está realmente destinada a convertir cadenas numéricas como " 123 " o "17.5e4" a los números equivalentes. La conversión primero omite los espacios en blanco iniciales (por lo que " 123 " es válido) y luego intenta analizar los restos como un número. Si no se puede analizar como un número (`` x '' no lo es), entonces el resultado es NaN. Pero existe la regla especial explícita de que una cadena que está vacía o solo un espacio en blanco se convierte a 0. Entonces esto explica la conversión.

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

Escribí esta pequeña función rápida para ayudar a resolver este problema.

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

Simplemente busca cualquier carácter que no sea numérico (0-9), que no sea '-' o '.', y que no esté indefinido, nulo o vacío y devuelva verdadero si no hay coincidencias. :)

La función JavaScript isNaN incorporada es, como debería esperarse de forma predeterminada, un " Operador de tipo dinámico " ;. Por lo tanto, todos los valores que (durante el proceso DTC) pueden producir un valor simple | falso como " " ;, " " ;, " 000 " , no puede ser NaN.

Significa que el argumento suministrado primero se someterá a una conversión como en:

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

Explicación :

En la línea superior del cuerpo de la función, (primero) estamos tratando de convertir con éxito el argumento en un objeto numérico. Y (segundo), usando el operador de punto, estamos, para nuestra conveniencia, quitando inmediatamente, el primitivo valor del objeto creado.

En la segunda línea, estamos tomando el valor obtenido en el paso anterior, y la ventaja del hecho de que NaN no es igual a nada en el universo, ni siquiera para sí mismo, por ejemplo: NaN == NaN > > falso para finalmente compararlo (por desigualdad) consigo mismo.

De esta forma, la función return arrojará true solo cuando, y solo si, el argumento-return proporcionado, es un intento fallido de conversión a un objeto numérico, es decir , un número que no es un número; por ejemplo, NaN.


isNaNstatic ()

Sin embargo, para un operador de tipo estático, si es necesario y cuando es necesario, podemos escribir una función mucho más simple como:

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

Y evite el DTC por completo, de modo que si el argumento no es explícitamente un número NaN, devolverá falso. Por lo tanto, prueba contra lo siguiente:

isNaNStatic (" x "); // devolverá falso porque sigue siendo una cadena.

Sin embargo: isNaNStatic (1 / " x "); // por supuesto devolverá true. como lo hará, por ejemplo, isNaNStatic (NaN); > > verdadero .

Pero a diferencia de isNaN , el isNaNStatic (" NaN "); > > false porque (el argumento) es una cadena normal.

p.s .: La versión estática de isNaN puede ser muy útil en escenarios de codificación modernos. Y bien puede ser una de las principales razones por las que me tomé mi tiempo para publicar esto.

Saludos.

isNAN (< argumento >) es una función para determinar si un argumento dado es un número ilegal. isNaN tipea los argumentos en el tipo de Número. Si desea verificar si el argumento es numérico o no? Utilice la función $ .isNumeric () en jQuery.

Es decir, isNaN (foo) es equivalente a isNaN (Number (foo)) Acepta cualquier cadena que tenga todos los números como números por razones obvias. Por ej.

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

Yo uso esto

    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 ! == " no es un número "

NaN es un valor de Tipo de número

esta es una definición de isNaN () en ECMAScript

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

Intenta convertir cualquier valor a Número.

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

Si desea determinar si el valor es NaN , primero debe intentar convertirlo en un valor Número.

Al verificar si cierto valor de cadena con espacios en blanco o " " es isNaN tal vez intente realizar la validación de la cadena, por ejemplo:

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top