de.front #002 O que acontece no algoritmo de igualdade do JS?
tags satisfies, NaN, css variables, strict equals, loosely equals
Opa! boas vindas a segunda edição do de.front! hoje vamos entender um pouco sobre uma função relativamente nova do typescript, o por que que o NaN é uma tipagem diferenciada, variáveis css e mais a fundo sobre como é o funcionamento dos algoritmos de igualdade.
<aside>
TS satisfies
Você já precisou montar um objeto e passar como argumento de uma funçao? já fez isso no typescript e percebeu como é chato? nessas situações normalmente precisamos "forçar" uma tipagem para que ele aceite como verdade:
const user = {
content: undefined,
name: "Jorge"
} as PrintContentProps // irá retornar erro no objeto como um todo, imagine aqui um objeto de vários e vários itens para entender qual o erro que está retornando
printContent(user)
function printContent(param: PrintContentProps) {
console.log(param.content)
}
interface PrintContentProps {
content: string;
nome: string
}
Agora mudando para o satisfies
:
const user = {
content: undefined, // será identificado somente aqui como um problema para que você faça o ajuste!
name: "Jorge"
} satisfies PrintContentProps
printContent(user)
function printContent(param: PrintContentProps) {
console.log(param.content)
}
interface PrintContentProps {
content: string;
nome: string
}
E ai, você pode me perguntar, por que devo trocar? bem, eu consideraria a ideia por que ele te dá essa visão mais clara do que está dando erro, podendo ver antes mesmo de colocar como um argumento na função, além disso, quando usamos o as
estamos informando que aquela é a tipagem, e dependendo da situação pode ocorrer de o programa aceitar que é aquele valor realmente é o correto, gerando problemas futuros 🐛
JS NaN
Sabia que valores NaN (Not a Number) não são iguais? pois é!
NaN === NaN // false
Tá mas por que isso acontece?
Na especificação do javascript, valores NaN
são considerados diferentes dele mesmo em qualquer aspecto, por que veja, a string computador
e array ['teclado']
não são iguais em praticamente nada, porém os dois não são números, logo os dois são NaN
s e já que existe essa certa igualdade eles poderiam ser considerados iguais de maneira errada
Ok, entendi, mas como que eu lido com isso no meu dia a dia?
Aqui a gente pode utilizar uma função que foi disponibilizada para nós que é o isNaN
, com um pequeno detalhe que posso entrar mais a fundo em outro momento, dê preferencia a função que vem do construtor Number
, dessa maneira:
Number.isNaN('computador') == Number.isNaN(['teclado']) // como o resultado é um boolean doss dois lado, eu posso garantir que os dois realmente não são números e gerar um grau de igualdade por conta disso!
CSS variables
Se você já teve problema e valores dentro do CSS e também já não conhece essa funcionalidade dele, podemos atribuir valores que nem fazemos com o javascript, quer dizer, mais ou menos por que precisa de uns detalhes a mais hehe
:root {
--var-1: #FFF;
}
div {
background-color: var(--var-1);
}
Você só precisa adicionar a iniciação dela, normalmente no pseudo elemento root utilizando a nomenclatura de dois hifens no inicio seguido do seu nome e para consumir esse conteúdo, é usar a função var()
com essa variável, o mais legal é que ela vai aparecer exatamente assim no dev tools dando maior visibilidade do que está acontecendo!
<main>
Agora para o assunto principal / polêmico que é o uso das igualdades!
Acredito que praticamente todos nós somos ensinados desde sempre que o javascript tem o loose equals ==
e o strict equals ===
e que se você usar o loose equals o seu programa entrará em combustão espontânea, que tudo que usamos será convertido para valores impossíveis e que devemos ter raiva das pessoas que usam essa expressão, e a única solução é trazer mais um sinal para que tudo se resolva de maneira perfeita, onde todos os problemas são resolvidos e nós devs fronts podemos viver felizes para sempre com nossas escolhas. Quero te mostrar um pouco mais por de baixo dos panos qual que é a diferença entre esses dois, e pasmem, como podemos também utilizar das funcionalidades que cada um nós dá, sim, vou te dar munição para poder usar um caractere a menos no seu programa!
Ok ok, agora entrando no conteúdo real, precisamos entender que, cada um tem seu algoritmo, ou conjunto de instruções, que vão definir como os valores de cada lado serão utilizados para chegar em um valor boolean de comparação final, termos um conceito mental de como funciona vai nós ajudar a entender quando utilizar cada um, já que são ferramentas que está à nosso dispor, então vou passar abaixo como são, começando pelo strict:
Para efeito dos exemplos estarei nomeando os valores comparados como
esquerda
edireita
para definir as duas opções que temos na comparação
algoritmo do strict equal ou ===
- Se tipo do
esquerda
for diferente dodireita
retornafalse
- Se tipo de
esquerda
for número então retorna comparação numérica entreesquerda
edireita
- Retorna comparador de mesmo mesmo valor que não seja numérica.
bastante simples né? aqui devemos ter cuidado somente com a comparação de NaNs como foi comentado anteriormente e comparação de objetos que podem ser iguais mas não tem a mesma referencia (que pode ser outro tópico futuro se você quiser).
algoritmo do loosely equal ou ==
- Se tipo
esquerda
for igual ao tipodireita
retorna algoritmo de validação strict - Se
esquerda
fornull
edireita
forundefined
retornatrue
- Se
esquerda
forundefined
edireita
fornull
retornatrue
- Se
esquerda
fornumber
edireita
forstring
, converte astring
paranumber
e reinicia o algoritmo - Se
esquerda
forstring
edireita
fornumber
, converte astring
paranumber
e reinicia o algoritmo - Se
esquerda
forbigint
edireita
forstring
, converte astring
parabigint
- Se a conversão resultar em
undefined
retornafalse
- Reinicia o algoritmo
- Se a conversão resultar em
- Se
esquerda
forstring
edireita
forbigint
reinicia o algoritmo porém trocando as posições deesquerda
edireita
- Se
esquerda
forboolean
converte ele paranumber
e reinicia o algoritmo - Se
direita
forboolean
converte ele paranumber
e reinicia o algoritmo - Se
esquerda
for qualquer um entrestring
,number
,bigint
ouSymbol
edireita
for umobject
convertedireita
para tipo primitivo e reinicia o algoritmo - Se
esquerda
for umobject
edireita
for qualquer um entrestring
,number
,bigint
ouSymbol
converteesquerda
para tipo primitivo e reinicia o algoritmo - Se
esquerda
forbigint
edireita
fornumber
ou o inverso, então:esquerda
OUdireita
forinfinity
retornafalse
esquerda
edireita
tem o mesmo valor e é finita, retornatrue
- retorna
false
Ufa! viu que é um algoritmo muito mais extenso? imagino que sim kk
Por ter tantas regras, faz com que tenhamos situações onde caso seu mapa mental não esteja alinhado com ele, gera um problemão de entendimento, porém se você entende bem isso aqui, facilita muito na hora de decidir e utilizar algumas dessas funcionalidades, lê novamente esse algoritmo e anota alguns pontos interessantes sobre ele.
Fez?
Bora falar desses pontos e ver se estamos alinhados:
Todos os caminhos levam a number
Com várias regras que o algoritmo tem, ele sempre tem a tendencia de tentar fazer o valor chegar em números, percebe? nos momentos em que ele reinicia o algoritmo, ele está convertendo de alguma maneira esse valor para o mais próximo de number que seja possível, assim é algo que você pode ficar em mente, em talvez como otimizar isso!
Infinitas não forma
Valores infinitos só são iguais com eles mesmos, então se um deles não for, o algoritmo nem se dá mais o trabalho
null e undefined são iguais???
Pois é! nesse algoritmo, os dois valores são considerados iguais, então poderíamos utilizar isso de alguma forma...
Calma, o que é aquela primeira instrução?
Simmm, eu propositalmente falei logo pelo strict equal por conta disso, logo na primeira instrução desse algoritmo, se os tipos forem iguais ele retorna a regra de strict!! então, se você já sabe quais são os tipos dos dois lados da igualdade, que espero que você sempre saiba kk, podemos utilizar do loose para entrar rapidamente na regra do strict, assim permitindo a mesma lógica no final das contas!
E ai viu mais algo interessante? me fala sobre!
Como usar isso ao nosso favor?
Como primeiro exemplo, eu comentei ali sobre o null
e undefined
e podemos fazer isso aqui:
Ao invés de:
if(content !== undefined && content !== null) {
return "conteúdo"
}
Podemos fazer:
if(content != null) {
return "conteúdo"
}
Legal né? já nós dá opções mais simples de utilizar
Já para o caso de você precisar utilizar o typeof
por exemplo:
if(typeof content == 'string') // já que as opções são sempre strings com o nome de cada um, não precisamos do = extra
Outro interessante é, não sei se você sabe, mas quando usamos um array vazio para fazer comparação, ele é considerado true e para isso precisamos utilizar o length
para checar o comprimento e estar tudo certo:
if([]) // true
if([].length) // false
Mas podemos utilizar da habilidade do algoritmo de transformar tudo em number
para chegar em algo que funcione para nós:
if([] != 0) // normalmente o array seria um valor truthy mas como comparamos com um número, esse obrigatoriamente é convertido, assim chegando no false!
// para comparação, utilizando o strict equal isso aqui seria true:
if([] !== 0) // tipos são diferentes? nem vou me dar o trabalho, é true!
Conclusão
Tentei fazer aqui uma defesa por essa parte do javascript que é tão marginalizada, e tem sim seus vários casos de uso, mas precisa ter também esse mapa mental ou algoritmo na cabeça quando for fazer suas validações, como um pesquisa sua, sabe quando aparecer aquelas regras consideradas malucas que gostam de tirar onda conosco, pega ela e passa por esse algoritmo para entender e passar esse conhecimento adiante!
Bônus
Lembra quando falei lá em cima sobre o isNaN
e como devemos dar preferência a função que vem do construtor Number
?
É por que a versão global do isNaN
utiliza da mesma lógica do algoritmo do loosely equals, forçando sempre a conversão para number
que é algo que pode ocasionar algumas lógicas meio confusas!
Então o pessoal lá nós deu o Number.isNaN
que não faz nenhum tipo de conversão, assim ficando mais simples e com casos de uso mais claros evitando bugs por falta de conhecimento.
<footer>
e aí? se você chegou até aqui, obrigado! fiquei muito feliz com as interações que tive na última postagens e quero continuar trazendo esse conteúdo para vocês para entrarmos cada vez mais no mundo do front end juntos!
me manda um feedback! gostou do conteúdo? quer ver mais? falei besteira? me avisa!
é nozes!