¿Cuál es la diferencia entre (NaN != NaN) y (NaN !== NaN)?

7 minutos de lectura

avatar de usuario
Giorgi Nakeuri

Antes que nada quiero mencionar que sé cómo isNaN() y Number.isNaN() trabajar. Estoy leyendo La guía definitiva por David Flanagan y da un ejemplo de cómo verificar si el valor es NaN:

x !== x

Esto resultará en true si y solo si x es NaN.

Pero ahora tengo una pregunta: ¿por qué usa la comparación estricta? porque parece que

x != x

se comporta de la misma manera. ¿Es seguro usar ambas versiones o me faltan algunos valores en JavaScript que devolverán true por x !== x y false por x != x?

  • Podría ser que Flanagan simplemente prefiera !== revisa != cheques Hasta donde yo sé, no hay otro valor donde x != x. Pero hay dos grupos distintos de desarrolladores de JavaScript: aquellos que prefieren != y los que prefieren !==ya sea por rapidez, claridad, expresividad, etc.

    – Steve Klösters

    14 de diciembre de 2015 a las 7:56


  • ¿Por qué usar la comparación flexible cuando la comparación estricta se comporta de la misma manera?

    – Ry-

    14 de diciembre de 2015 a las 8:06

  • @Rauluco: NaN no es un tipo único, es un número. es unico valor que no es igual a si mismo.

    –TJ Crowder

    14 de diciembre de 2015 a las 9:15

  • El título parece estar engañando a la gente. Sugeriría cambiarlo a algo como “¿Es x != x alguna vez diferente de x !== x?”

    –TJ Crowder

    14 de diciembre de 2015 a las 9:16


  • @femmestem: Giorgi dijo “en este caso” es una cuestión de estilo. Y tiene razón en eso. Eso no es estilo cuando los tipos de los operandos son diferentes, pero es estilo cuando son iguales. Por separado: Flanagan está haciendo esas comparaciones con === con NaN para hacer el punto que NaN no es igual a sí mismo. No está “equivocado”, lo está haciendo como un ejercicio de enseñanza, demostrando que no funciona.

    –TJ Crowder

    14 de diciembre de 2015 a las 9:39


avatar de usuario
TJ Crowder

En primer lugar, permítanme señalar que NaN es un valor muy especial: por definición, no es igual a sí mismo. Eso proviene del estándar IEEE-754 en el que se basan los números de JavaScript. El valor “no es un número” nunca es igual a sí mismo, incluso cuando los bits coinciden exactamente. (Que no están necesariamente en IEEE-754, permite múltiples valores diferentes “no un número”). Es por eso que incluso surge esto; todos los demás valores en JavaScript son iguales a ellos mismos, NaN es simplemente especial.

… ¿me falta algún valor en JavaScript que devolverá verdadero para x !== x y falso para x != x?

No tu no eres. La única diferencia entre !== y != es que este último hará coerción de tipos si es necesario para que los tipos de los operandos sean los mismos. En x != xlos tipos de los operandos son los mismos, por lo que es exactamente lo mismo que x !== x.

Esto queda claro desde el comienzo de la definición de la Operación de igualdad abstracta:

  1. Devolver si es abrupto (x).
  2. ReturnIfAbrupt(y).
  3. Si Tipo(x) es lo mismo que Tipo(y), entonces

    Devuelve el resultado de realizar la Comparación de igualdad estricta x === y.

Los primeros dos pasos son plomería básica. Entonces, en efecto, el primer paso de == es ver si los tipos son los mismos y, si es así, hacer === en cambio. != y !== son solo versiones negadas de eso.

Entonces, si Flanagan tiene razón en que solo NaN dará verdad por x !== xpodemos estar seguros de que también es cierto que sólo NaN dará verdad para x != x.

Muchos programadores de JavaScript usan por defecto === y !== para evitar algunas trampas en torno al tipo de coerción que hacen los operadores flexibles, pero no hay nada que leer en el uso de Flanagan del operador estricto frente al operador flexible en este caso.

  • he releído 4.9.1 - Equality and Inequality Operators y esta parece ser la respuesta. El punto clave para === la comparación es: If the two values have the same type, test them for strict equality as described above. If they are strictly equal, they are equal. If they are not strictly equal, they are not equal.

    – Giorgi Nakeuri

    14 de diciembre de 2015 a las 9:27

  • @GiorgiNakeuri: No estoy seguro de a qué 4.9.1 te refieres, ¿quizás al libro de Flanagan? Pero eso básicamente dice lo que dice la cita de la especificación anterior, sí.

    –TJ Crowder

    14 de diciembre de 2015 a las 9:32

  • Acepto esto porque responde a mi pregunta de manera formal y precisa. ¡Gracias por las explicaciones!

    – Giorgi Nakeuri

    14 de diciembre de 2015 a las 10:01

  • @Moshe: ¿Qué quiere decir con “enlaces en vivo”? (El término no aparece en la especificación). ¿Quiere decir algo como el ejemplo de GOTO 0 donde a es en realidad una función y no devuelve el mismo valor dos veces? Eso no es lo mismo que un valor para cual !== sería cierto, que es lo que preguntó el OP. Es solo una función que devuelve diferentes valores. foo() !== foo() tampoco es necesariamente cierto, ya que foo podría devolver valores diferentes en cada llamada.

    –TJ Crowder

    14/12/2015 a las 18:30


  • @Moshe Bueno, esa es una forma súper desagradable de meterse con propiedades y captadores. Pero parece ser más o menos lo mismo que el ejemplo de GOTO 0, solo con una capa adicional de direccionamiento indirecto.

    – JAB

    14 de diciembre de 2015 a las 21:18


avatar de usuario
jkdev

A efectos de NaN, != y !== hacer la misma cosa.

Sin embargo, muchos programadores evitan == o != en JavaScript. Por ejemplo, Douglas Crockford los considera entre los “partes malas” del lenguaje JavaScript porque se comportan de formas inesperadas y confusas:

JavaScript tiene dos conjuntos de operadores de igualdad: === y !==y sus gemelos malvados == y !=. Los buenos funcionan como cabría esperar.

… Mi consejo es nunca usar a los gemelos malvados. En su lugar, utilice siempre === y !==.

  • La pregunta no es sobre NaN (a pesar del título). La pregunta es “¿Me estoy perdiendo algún valor en JavaScript que devolverá verdadero para x! == x y falso para x! = x?”

    –TJ Crowder

    14 de diciembre de 2015 a las 9:12

  • @TJCrowder Dos preguntas, de verdad. La primera pregunta es “¿Es seguro usar ambas versiones?” y la respuesta es que ambas versiones son equivalentes. Me gusta su respuesta “bajo el capó” que explica todo en detalle.

    – jkdev

    14 de diciembre de 2015 a las 10:08


avatar de usuario
IR A 0

Solo por diversión, déjame mostrarte un ejemplo artificial donde x no es NaN pero los operadores se comportan de manera diferente de todos modos. Primero define:

Object.defineProperty(
  self,
  'x',
  { get: function() { return self.y = self.y ? 0 : '0'; } }
);

Entonces tenemos

x != x // false

pero

x !== x // true

  • ¡Decir ah! 🙂 Pero eso es efectivamente foo() != foo() donde foo devuelve 1 y luego 2. Por ejemplo, el valores no son lo mismo, es solo comparar diferentes valores.

    –TJ Crowder

    14 de diciembre de 2015 a las 10:09

solo quiero señalar NaN no es lo único que produce x !== x sin utilizar el objeto global. Hay muchas formas inteligentes de desencadenar este comportamiento. Aquí hay uno que usa captadores:

var i = 0, obj = { get x() { return i++; }};
with(obj) // force dynamic context, this is evil. 
console.log(x === x); // false

Como señalan otras respuestas, == realiza coerción de tipos, pero al igual que en otros lenguajes y a la par del estándar, NaN indica una falla de cálculo y, por buenas razones, no es igual a sí mismo.

Por alguna razón más allá de mí, la gente considera que esto es un problema con JS, pero la mayoría de los lenguajes que tienen dobles (es decir, C, Java, C ++, C #, Python y otros) exhiben este comportamiento exacto y la gente está de acuerdo con eso.

Como a veces, las imágenes son mejores que las palabras, mira esto mesa (que es la razón por la que hago de esto una respuesta en lugar de un comentario porque tiene una mejor visibilidad).

Allí puede ver que la comparación de igualdad estricta (===) solo devuelve verdadero si el tipo y el contenido coinciden, por lo que

var f = "-1" === -1; //false

Mientras que la comparación de igualdad abstracta (==) verifica solo el contenido* al convertir tipos y luego compararlos estrictamente:

var t = "-1" == -1; //true

Aunque no está claro, sin consultar ECMAlo que JavaScript considera al comparar, de manera que el siguiente código se evalúe como verdadero.

 var howAmISupposedToKnowThat = [] == false; //true

¿Ha sido útil esta solución?