The Abstract Equality Comparison Algorithm
Jessuir Cleydson
Posted on March 6, 2023
Revisitando alguns assuntos bases do JavaScript percebi a necessida de aprofundar um pouco mais a teoria de como as coisas funcionam behind the scenes.
Vou tentar trazer aqui um resumo sobre a interação do "Algoritmo de comparação de igualdade" ou como o JavaScript chama "The Abstract Equality Comparison Algorithm" e o "Type Coercion". Em outras palavras eu quero tentar explicar como o ==
(igual a) entende os parâmetros passados a ele para comparação de igualdade.
Inicio esse artigo considerando que se você chegou aqui você entende o que é o ==
no JavaScript. Mas caso tenha caído aqui de paraquedas segue um link para conhecer antes de ler o meu texto.
x ==
y
Sabemos então que esse operador recebe dois parâmetros e compara seus valores, simples assim, ou será que não?
Para nós que apenas vemos o resultado final é tudo muito mágico e simples mas as vezes podemos nos deparar com algumas situações (ou evitá-las) se conhecermos um poco mais como a "mágica" funciona.
Vou utilizar um exemplo que retirei do livro You Don't Know Js
let arr1 = [1,2,3];
let arr2 = [1,2,3];
let str = "1,2,3";
Em um primeiro momento podemos dizer que visualmente arr1
é igual a arr2
e os dois são diferentes de str
, correto?
Acontesse que quando os comparamos utilizando o ==
temos uma pequena surpresa.
arr1 == str; // true
arr2 == str; // true
arr1 == arr2; // false
Descobrimos que na verdade arr1
é diferente de arr2
porém os dois são iguais a str
. Como pode isso?
Poderíamos apenas aceitar que é assim que funciona o JavaScript e seguir com nossas vidas, mas se você está curioso para entender porquê [1,2,3] é diferente de [1,2,3]
continua lendo aqui...
Legal você ficou, vamos lá!
Cavando um pouco mais fundo esbarramos com dois outros temas: Type Coercion e The Abstract Equality Comparison Algorithm.
Abaixo vou te dar um breve resumo sobre o Type Coercion para em seguida entendermos como ele se aplica no segundo, e mais importante, tema.
Type Coercion
O Type Coercion
é a forma como o JavaScript converte o tipo de um valor para outro tipo de forma "automática" e implícita.
Podemos ver isso quando tentamos somar um número com um texto ou na linguagem de tipos seria um number
com uma string
Nesse momento para evitar qualquer quebra na execução do código o Type Coercion
decide que o valor 12
do tipo number
vai ser convertido para string
e em vez de somar ele concatena os dois valores em uma única string garantindo a execução do código.
O javaScript então se utiliza de algoritmos próprios para decidir e priorizar qual valor ele deve converter para que o código possa ser executado com sucesso.
Não vou me prolongar mais sobre o Type Coercion porque até aqui é suficiente para entender o próximo e principal tópico. Quem sabe eu trago um artigo só sobre ele no futuro.
The Abstract Equality Comparison Algorithm
Chegamos então no X da questão
Esse algoritmo abstrato nada mais é que a forma como o javaScript aplica o Type Coercion
no momento da comparação de ==
(igual a) e entender isso te permite manipular melhor ou com mais certeza seu código e evitar aqueles momentos onde o código funciona por pura mágica.
Behind the scenes ele vai tentar comparar os valores dos paramêtros x == y
e quando algo que não deveria acontecer, acontece, ele te da uma ajuda convertendo os tipos dos valores. Com isso ele aplica seu algoritmo de comparação de igualdade onde ele classifica prioridades de conversão e cria condições para que elas sejam aplicadas.
No tópico 11.9.3 da especificação do JavaScript ele institui que:
Se o X é Object e o Y é uma String ou Number, retorna o resultado da comparação de ToPrimitive(x) == y.
O que ele quer dizer com isso?
Ele ta dizendo que se no código que você escreveu [1,2,3] == "1,2,3"
o X= [1,2,3]
for um objeto e o Y= "1,2,3"
for uma String ou Number ele vai tentar converter o valor de X (por trás dos panos) para um valor primitivo usando o Type Coercion
, que vimos anteriormente, e depois da conversão comparar os valores.
Se você ficou confuso com a palavra primitivo segue um link pra entender melhor o parágrafo anterior.
Nesse ponto começamos a ter uma boa dica para entender o motivo de [1,2,3] ser igual a "1,2,3"
ou como em nosso exemplo arr1 == str // true
.
Olha só! Quando utilizamos o typeof para verificar o tipo dos valores do nosso exemplo do começo desse artigo, descobrimos que o arr1
e arr2
são objetos e o str
é string logo a comparação de arr1 == str
cai na condição que o algoritmo de comparação de igualdade instituiu.
typeof arr1 // object
typeof arr2 // object
typeof str // string
Você ja deve está entendendo onde eu quero chegar... Vamos então entender nosso exemplo do início do artigo.
arr1 == str; // true
arr2 == str; // true
arr1 == arr2; // false
Na primeira linha ele compara arr1
, que é um object
, com str
que é string
, então, antes de tudo, converte arr1
para string
e então comparando os dois valores temos o resultado de true
pois os dois valores são iguais no final. E aqui quero abrir um parênteses para você entender melhor como ele faz essa conversão.
Todo valor do tipo objeto tem um método interno chamado toString
e é justamente esse metodo que o javaScript se utiliza para fazer as conversões por meio do Type Coercion de forma implícita. Mas nós também podemos fazer de forma explícita para ficar mais visível.
arr1.toString() // "1,2,3"
Olha só, se chamamos o método toString do objeto arr1
temos como resultado exatamente o mesmo valor da variável str
por isso o resultado da comparação de arr1 == str é true
, no fim eles possuem o mesmo valor. A mesmo coisa se aplica para arr2 == str
.
A última linha de nosso exemplo diz que arr1 == arr2 é false
e isso acontece porque a especificação 11.9.3 diz que ele só converte o valor do objeto caso um dos valores fosse object
e o outro string
ou number
. Nessa comparação que estamos fazendo agora os dois são object
.
typeof arr1 // object
typeof arr2 // object
Então essa comparação cai em outra condicional instituida pela especificação 11.9.3.
Logo como ele não vai converter nem X e nem Y pois os dois são object
ele vai retorna false
pois o valor do objeto é ele próprio e cada objeto instanciado é diferente um do outro mesmo possuindo as mesmas propriedades.
Se quiser entender mais sobre objetos esse link pode te ajudar.
Por fim, vimos então que uma simples comparação ==
passa por um algoritmo que vai:
- Verificar os tipos dos valores dos parâmetros passados;
- Ver em qual condição se encaixam;
- Converter os tipos dos valores;
- Para só então comparar um com o outro.
E se eu te mostrar novamente o mesmo exemplo do início desse artigo?
let arr1 = [1,2,3];
let arr2 = [1,2,3];
let str = "1,2,3";
arr1 == str; // true
arr2 == str; // true
arr1 == arr2; // false
Espero que olhando para ele agora não apenas venha na sua cabeça "não entendi mas é assim que funciona" mas que agora faça sentido para você o resultado de cada comparação entendendo o que acontece por trás dos panos e com isso possa melhorar os seus códigos.
Links úteis
- Especificação do Algoritimo de comparação de igualdade
- Especificação do metodo implícito ToPrimitive()
- Especificação de como o JavaScript prioriza a conversão dos valores dos objetos
Se esse post te ajudou em algo, deixa um comentário ou um Like pra ajudar no engajamento :D
Posted on March 6, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.