Como matemático profesional, veo en el operador de igualdad de Javscript ==
(también llamado "comparación abstracta", "igualdad suelta" ) un intento de construir una relación de equivalencia entre entidades, que incluye ser reflexivo , simétrico y transitivo . Desafortunadamente, dos de estas tres propiedades fundamentales fallan:
A == A
puede ser falso, por ejemplo
NaN == NaN // false
A == B
y B == C
juntos no implican A == C
, por ejemplo
'1' == 1 // true
1 == '01' // true
'1' == '01' // false
Solo la propiedad simétrica sobrevive:
A == B
implica B == A
, qué violación es probablemente impensable en cualquier caso y conduciría a una rebelión grave;)
¿Por qué importan las relaciones de equivalencia?
Porque ese es el tipo de relación más importante y frecuente, respaldado por numerosos ejemplos y aplicaciones. La aplicación más importante es la descomposición de entidades en clases de equivalencia , que es en sí misma una forma muy conveniente e intuitiva de entender las relaciones. Y no ser equivalencia conduce a la falta de clases de equivalencia, lo que a su vez conduce a la falta de intuición y complejidad innecesaria que es bien conocida.
¿Por qué es una idea tan terrible escribir ==
para una relación de no equivalencia?
Porque rompe nuestra familiaridad e intuición, ya que literalmente cualquier relación interesante de similitud, igualdad, congruencia, isomorfismo, identidad, etc. es una equivalencia.
Conversión de tipo
En lugar de confiar en una equivalencia intuitiva, JavaScript introduce la conversión de tipos:
El operador de igualdad convierte los operandos si no son del mismo tipo, luego aplica una comparación estricta.
Pero, ¿cómo se define la conversión de tipo? ¿A través de un conjunto de reglas complicadas con numerosas excepciones?
Intento de construir una relación de equivalencia
Booleanos. Claramente true
y false
no son lo mismo y deben estar en diferentes clases.
Números. Afortunadamente, la igualdad de números ya está bien definida, en la que dos números diferentes nunca están en la misma clase de equivalencia. En matemáticas, eso es. En JavaScript, la noción de número está algo deformada por la presencia de los más exóticos -0
, Infinity
y -Infinity
. Nuestra intuición matemática dicta que 0
y -0
debe estar en la misma clase (de hecho lo -0 === 0
es true
), mientras que cada uno de los infinitos es una clase separada.
Números y booleanos. Dadas las clases de números, ¿dónde ponemos los booleanos? false
se vuelve similar a 0
, mientras que se true
vuelve similar a, 1
pero no a otro número:
true == 1 // true
true == 2 // false
¿Hay alguna lógica aquí para true
armar 1
? Es cierto que 1
se distingue, pero también lo es -1
. Yo personalmente no veo ninguna razón para convertir true
a 1
.
Y se pone aún peor:
true + 2 // 3
true - 1 // 0
Por true
lo tanto, de hecho se convierte 1
entre todos los números! ¿Es lógico? ¿Es intuitivo? La respuesta se deja como ejercicio;)
Pero qué hay de esto:
1 && true // true
2 && true // true
El único booleano x
con x && true
ser true
es x = true
. Lo que demuestra que tanto 1
y 2
(y cualquier otro número que 0
) se convierten a true
! Lo que muestra es que nuestra conversión falla otra propiedad importante: ser biyección . Lo que significa que dos entidades diferentes pueden convertir a la misma. Lo cual, por sí mismo, no tiene que ser un gran problema. El gran problema surge cuando usamos esta conversión para describir una relación de "similitud" o "igualdad suelta" de lo que queramos llamarlo. Pero una cosa está clara: no será una relación de equivalencia y no se describirá intuitivamente a través de clases de equivalencia.
¿Pero podemos hacerlo mejor?
Al menos matemáticamente, ¡definitivamente sí! Se podría construir una relación de equivalencia simple entre booleanos y números con solo false
y 0
estar en la misma clase. Entonces false == 0
sería la única igualdad suelta no trivial.
¿Qué pasa con las cuerdas?
Podemos recortar cadenas de espacios en blanco al principio y al final para convertirlas en números, también podemos ignorar ceros al frente:
' 000 ' == 0 // true
' 0010 ' == 10 // true
Entonces obtenemos una regla simple para una cadena: recortar los espacios en blanco y los ceros al frente. O obtenemos un número o una cadena vacía, en cuyo caso la convertimos a ese número o cero. O no obtenemos un número, en cuyo caso no convertimos y, por lo tanto, no obtenemos una nueva relación.
¡De esta forma podríamos obtener una relación de equivalencia perfecta en el conjunto total de booleanos, números y cadenas! Excepto que ... los diseñadores de JavaScript obviamente tienen otra opinión:
' ' == '' // false
¡Entonces las dos cadenas a las que ambos se convierten de 0
repente no son similares! ¿Por qué o por qué? De acuerdo con la regla, las cadenas son más o menos iguales precisamente cuando son estrictamente iguales. ¡No solo esta regla rompe la transitividad como vemos, sino que también es redundante! ¿Cuál es el punto de crear otro operador ==
para que sea estrictamente idéntico al otro ===
?
Conclusión
El operador de igualdad flexible ==
podría haber sido muy útil si respetara algunas leyes matemáticas fundamentales. Pero como lamentablemente no, su utilidad sufre.