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í:
- Si Type(x) es el mismo que Type(y), entonces devuelve x === y.
- Comparar
null
y undefined
siempre es true
- Si Type(x) es Number y Type(y) es String, devuelve x == ToNumber(y).
- Si Type(x) es String and Type(y) es Number, devuelve ToNumber(x) == y.
- Si Type(x) es Boolean, devuelve ToNumber(x) == y.
- Si Type(y) es Boolean, devuelve x == ToNumber(y).
- Si Type(x) es String, Number, o Symbol y Type(y) es Object, devuelve x == ToPrimitive(y).
- Si Type(x) es Object y Type(y) es String, Number, o Symbol, devuelve ToPrimitive(x) == y.
- 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