== no siempre hace transformación de tipos
Cuando hacemos una igualdad usando ==
mucha gente cree que JavaScript usa la coerción de datos para comparar ambos valores. Pero lo cierto es que no es exactamente así. Al usar este tipo de igualdad, lo que ocurre en realidad, es que entra en acción otro tipo de mecanismo.
El mecanismo consiste en una serie de pasos y comprobaciones para identificar si la igualdad es cierta o no y, sólo en ocasiones, utiliza la coerción de datos para poder comparar ambos valores. Gracias a esto, ocurren cosas como esta:
2 == "2"; // true
true == 1; // true
"" == 0; // true
undefined == null; // true
"true" == true; // true
"false" == false; // false
Sabemos que hay transformación de tipos de datos, de String a Number o viceversa, porque estamos haciendo comparaciones entre tipos distintos y, sin embargo, JavaScript nos está diciendo que algunas condiciones son verdaderas.
Así que entendemos que se ejecuta un proceso para hacer la transformación de estos datos pero seguramente desconoces exactamente el algoritmo hay detrás para determinar este resultado.
Y es que… ¿por qué null == 0
es entonces false
? ¿No hace ahí una coerción de tipos?
Explicación del algoritmo de comparación en ==
El algoritmo tiene nombre y se llama Abstract Equality Comparison Algorithm (Algoritmo de comparación de Igualdad Abstracta) y está bien documentado.
La regla dice que en una comparación x == y
, donde x
e y
son valores, devolverá true
o false
…
- Si
x
ey
son del mismo tipo:- Si
x
esundefined
onull
devolverátrue
- Si
x
es unNumber
entonces:- Si
x
oy
esNaN
entonces devolveráfalse
. - Si
x
es el mismo valor numérico quey
devolverátrue
- Si
x
es 0 ey
es 0, independientemente de su signo, devolverátrue
. - En cualquier otro caso, será
false
- Si
- Si
x
esString
entonces serátrue
six
ey
tienen la misma secuencia de carácteres (misma longitud y posición). Si no, seráfalse
. - Si
x
esBoolean
entonces devolverátrue
si ambos sontrue
o ambos sonfalse
. Si no, seráfalse
. - Si
x
ey
están referenciando al mismo objeto serátrue
, si nofalse
.
- Si
- Si
x
esnull
ey
esundefined
serátrue
. - Si
y
esundefined
ey
esnull
serátrue
. - Si
x
esNumber
ey
esString
devuelve el resultado de compararx == Number(y)
- Si
x
esString
ey
esNumber
devuelve el resultado de compararNumber(x) == y
- Si
x
esBoolean
, devuelve el resultado de compararNumber(x) == y
- Si
y
esBoolean
, devuelve el resultado de compararx == Number(y)
- Si
x
esString
oNumber
ey
esObject
devuelve el resultado de compararx == toPrimitive(y)
- Si
x
esObject
ey
esString
oNumber
devuelve el resultado de comparartoPrimitive(x) == x
- El resto de casos devuelve
false
Cuando un Object (un objeto, array, function…) se convierte al primitivo… es muy tricky. Por ejemplo, al comparar un string con un array, el array pasaría a ser un String y al convertir un array vacio a string es un string vacio. En cambio el objeto {} a string pasa a ser “[object Object]“.
Como ves, el algoritmo no hace sólo una conversión de tipos y ya está. Es bastante más complejo que eso y, en ocasiones, ni siquiera es necesario transformar los tipos.
Si siempre hiciese coerción de datos null == 0
sería true
pero en cambio es false
pero si hicieramos Number(null) == 0
o Boolean(null) == 0
sí que serían ambos true
. Así que ya ves que no es correcto decir que ==
hace una coerción de los tipos a secas… si no que entra en juego un algoritmo de comparación de igualdad más complejo (y documentado).
De esta forma ya puedes probar a seguir este algoritmo para determinar igualdades con ==
para determinar qué resultado te va a esperar. De hecho, te dejo aquí una lista para que practiques… ¡a ver qué tal!
Práctica de comparación de igualdad con ==
window.midudev == null;
"si" == "si";
"talvez" == " talvez";
"null" == null;
null == "null";
undefined == 0;
null == 0;
2 == "2";
"[object Object]" == { a: "b" };
({ a: "b" }) == "[object Object]";
"" == [];
"" == {};