Como matemático profissional, vejo no operador de uniformidade de Javscript ==
(também chamado de "comparação abstrata", "igualdade frouxa" ) uma tentativa de construir uma relação de equivalência entre entidades, que inclui ser reflexiva , simétrica e transitiva . Infelizmente, duas dessas três propriedades fundamentais falham:
A == A
pode ser falso, por exemplo
NaN == NaN // false
A == B
e B == C
juntos não implicam A == C
, por exemplo,
'1' == 1 // true
1 == '01' // true
'1' == '01' // false
Somente a propriedade simétrica sobrevive:
A == B
implica B == A
, que violação é provavelmente impensável em qualquer caso e levaria a uma rebelião séria;)
Por que as relações de equivalência são importantes?
Porque esse é o tipo de relação mais importante e predominante, suportado por vários exemplos e aplicativos. A aplicação mais importante é a decomposição de entidades em classes de equivalência , que por si só é uma maneira muito conveniente e intuitiva de entender as relações. E a falta de equivalência leva à falta de classes de equivalência, o que, por sua vez, leva à falta de intuitividade e complexidade desnecessária que é bem conhecida.
Por que é uma péssima idéia escrever ==
para uma relação de não equivalência?
Porque rompe nossa familiaridade e intuição, pois literalmente qualquer relação interessante de similaridade, igualdade, congruência, isomorfismo, identidade etc. é uma equivalência.
Conversão de tipo
Em vez de confiar em uma equivalência intuitiva, o JavaScript introduz a conversão de tipo:
O operador de igualdade converte os operandos se não forem do mesmo tipo e aplica uma comparação estrita.
Mas como é definida a conversão de tipo? Através de um conjunto de regras complicadas, com inúmeras exceções?
Tentativa de construir relação de equivalência
Booleanos. Claramente true
e false
não são iguais e devem estar em classes diferentes.
Números. Felizmente, a igualdade de números já está bem definida, na qual dois números diferentes nunca estão na mesma classe de equivalência. Em matemática, é isso. Em JavaScript, a noção de número é um pouco deformada pela presença dos mais exóticos -0
, Infinity
e -Infinity
. Nossa intuição matemática determina que 0
e -0
deve estar na mesma classe (de fato -0 === 0
é true
), enquanto que cada um dos infinitos é uma classe separada.
Números e booleanos. Dadas as classes numéricas, onde colocamos booleanos? false
torna-se semelhante a 0
, enquanto true
torna-se semelhante a, 1
mas nenhum outro número:
true == 1 // true
true == 2 // false
Existe alguma lógica aqui para colocar true
junto com 1
? É certo que 1
se distingue, mas também é -1
. Eu pessoalmente não vejo qualquer razão para converter true
para 1
.
E fica ainda pior:
true + 2 // 3
true - 1 // 0
Então, de true
fato, é convertido em 1
entre todos os números! Isso é lógico? É intuitivo? A resposta é deixada como exercício;)
Mas e quanto a isso:
1 && true // true
2 && true // true
O único booleano x
com o x && true
ser true
é x = true
. O que prova que ambos 1
e 2
(e qualquer outro número que 0
) sejam convertidos para true
! O que mostra é que nossa conversão falha em outra propriedade importante - a bijeção . Significando que duas entidades diferentes podem ser convertidas na mesma. O que, por si só, não precisa ser um grande problema. O grande problema surge quando usamos essa conversão para descrever uma relação de "semelhança" ou "igualdade frouxa" do que queremos chamar. Mas uma coisa é clara - não será uma relação de equivalência e não será descrita intuitivamente por meio de classes de equivalência.
Mas podemos fazer melhor?
Pelo menos matematicamente - definitivamente sim! Uma simples relação de equivalência entre booleanos e números poderia ser construída com apenas false
e 0
estar na mesma classe. Assim false == 0
seria a única igualdade frouxa não trivial.
E as cordas?
Podemos cortar strings de espaços em branco no início e no final para converter em números, também podemos ignorar zeros na frente:
' 000 ' == 0 // true
' 0010 ' == 10 // true
Portanto, temos uma regra simples para uma string - apare os espaços em branco e os zeros na frente. Ou obtemos um número ou uma sequência vazia; nesse caso, convertemos para esse número ou zero. Ou não obtemos um número; nesse caso, não convertemos e, portanto, não obtemos nova relação.
Dessa forma, poderíamos obter uma relação de equivalência perfeita no conjunto total de booleanos, números e seqüências de caracteres! Exceto que ... Os designers de JavaScript obviamente têm outra opinião:
' ' == '' // false
Portanto, as duas seqüências para as quais os dois convertem 0
são subitamente semelhantes! Porque ou porque? De acordo com a regra, as strings são fracamente iguais exatamente quando são estritamente iguais! Não apenas essa regra quebra a transitividade como vemos, mas também é redundante! Qual o sentido de criar outro operador ==
para torná-lo estritamente idêntico ao outro ===
?
Conclusão
O operador de igualdade frouxa ==
poderia ter sido muito útil se estivesse cumprindo algumas leis matemáticas fundamentais. Mas como infelizmente não, sua utilidade sofre.