4

Tengo las siguientes expresiones en JavaScript y me gustaría saber, de forma mas detallada, el por qué de sus resultados.

[] == ''    // -> true
[] == 0     // -> true
[''] == ''  // -> true
[0] == 0    // -> true
[0] == ''   // -> false
[''] == 0   // -> true

[null] == ''        //true
[null] == 0         //true
[undefined] == ''   //true
[undefined] == 0    //true

[[]] == 0   //true
[[]] ==''   //true  

[[[[[[]]]]]] == 0   //true
[[[[[[]]]]]] == ''  //true

[[[[[[ null ]]]]]] == 0 //true
[[[[[[ null ]]]]]] == 0 //true

[[[[[[ undefined ]]]]]] == 0    //true
[[[[[[ undefined ]]]]]] == 0    //true

Mis dudas han surgido a partir de este meme:

meme

¿Porque esto no debería ser posible?

Mariano
  • 23,777
  • 20
  • 70
  • 102
Lombarda Arda
  • 1,904
  • 2
  • 20
  • 39
  • 3
    [Existe una pregunta que puede ayudar con sus dudas sobre estos detalles de JavaScript](https://es.stackoverflow.com/questions/66292/c%C3%B3mo-funciona-el-condicional-if-2-en-javascript/66296#66296) – Dev. Joel Feb 02 '18 at 11:13
  • @Davlio yo no lo consideraria duplicado ya que las expresiones son distintas, aunque las respuestas si que pueden servir como ayuda. A mi me gustaria una explicación de estas expresiones. – Lombarda Arda Feb 02 '18 at 11:23
  • @Dev.Joel como dices, puede servir de ayuda pero no creo que llegue a poder explicar todo – Lombarda Arda Feb 02 '18 at 11:36
  • 2
    @LombardaArda "Todo" no creo que encuentres en un solo lugar, aunque como base como dije antes es más que interesante. – Dev. Joel Feb 02 '18 at 11:43
  • @Dev.Joel por supuesto, me sirve como base y responde a alguna de las expriesiones, pero ¿Esa respuesta responde a mi pregunta? Yo creo que no, sirve como base, ayuda, punto de inicio pero no como un respuesta, ademas que tambien seria interesante que en la respuesta se comente la gracia del meme . – Lombarda Arda Feb 02 '18 at 11:49
  • 1
    "¿Por qué esto no debería ser posible?" el meme simplemente trata de exagerar las conversiones entre datos (cast). Una matriz vacía al convertirse a booleano da `false`, un 0 al convertirse a booleano es false, por lo que `false == false` es cierto (`true`). Podemos meterle tantas dimensiones a la matriz como queramos (`[]`, `[[]]`, `[[[]]]`, etc), seguirá convirtiéndose en siendo false y manteniéndose cierta la igualdad. Igualmente una cadena de caracteres vacía se convierte en `false`. Te podemos dar referencias a las conversiones entre datos, fallarían estrepitosamente con `===`. – OscarGarcia Feb 08 '18 at 10:33

1 Answers1

3

La explicación es sencilla, el comparador A==B funciona de la siguiente manera:

Si el tipo de A es igual al tipo de B, sencillamente comprueba que los valores son iguales. Si el tipo de A es null o undefined, la igualdad es verdad si B es null o undefined, en cualquier otro caso es falsa. Si los tipos son distintos, primero hace una conversión de A y/o B para que los tipos sean iguales:

String A == Number B -> toNumber(A) === Number B

Object A == Number B ->  toString(A) == toString(B) || toNumber(A)  === B

Puedes ver el algoritmo completo en la web del Estándar ECMAScript, aunque lo añado aquí:

  1. Si Type(x) es el mismo que Type(y), entonces devuelve x === y.
  2. Comparar null y undefined siempre es true
  3. Si Type(x) es Number y Type(y) es String, devuelve x == ToNumber(y).
  4. Si Type(x) es String and Type(y) es Number, devuelve ToNumber(x) == y.
  5. Si Type(x) es Boolean, devuelve ToNumber(x) == y.
  6. Si Type(y) es Boolean, devuelve x == ToNumber(y).
  7. Si Type(x) es String, Number, o Symbol y Type(y) es Object, devuelve x == ToPrimitive(y).
  8. Si Type(x) es Object y Type(y) es String, Number, o Symbol, devuelve ToPrimitive(x) == y.
  9. En cualquier otro caso, devuelve false.

Como un array es un objeto, tenemos que, al intentar transformarlo en un número, funciona así:

let a=[]; 
let b=[0,1,2];
let c=[2];

console.log(+a); //vacío, devuelve 0
console.log(+b); //muchos valores, Not a Number
console.log(+c); // un valor, se devuelve ese valor

Puesto que [] se transforma en 0 y [A] se transforma en toNumber(A), tenemos que [[]] pasa a ser [0] que, a su vez, pasa a ser 0.

Por tanto [[...[]...]] siempre es cero.

Del mismo modo, null y undefined se transforman en 0

Por tanto:

¿Porque esto no debería ser posible?

Es posible y una vez que lo entiendes tiene cierta lógica. Para evitar comportamientos como éste siempre puedes usar ===en lugar de ==. Lo que pasa es que

Javascript es el lenguaje más malentendido del mundo - Douglas Crockford, 2001

Pablo Lozano
  • 45,934
  • 7
  • 48
  • 87
  • Cuando dices: _"Si los tipos son distintos, primero hace una conversión de A y/o B para que los tipos sean iguales"_. ¿Cuál es la prioridad de tipos para realizar la conversión implícita, porqué consideraría `toNumber(A) === Number B` y no `A === toString(B)`? – Davlio Feb 02 '18 at 23:33
  • @Davlio añado un enlace para responder a tu duda – Pablo Lozano Feb 04 '18 at 16:59