O uso de If...Else
é um debate constante na comunidade dev. Muitos desenvolvedores não veem problema em utilizá-los, enquanto outros preferem abordagens como early return ou switch case. Mas e se eu te dissesse que existe uma alternativa mais elegante e eficiente?
Isso mesmo, utilize hashtables!
O que é uma Hashtable?
Na programação, uma hashtable (também conhecida como tabela de hash ou tabela de dispersão) é uma estrutura de dados que associa chaves a valores, permitindo buscas em tempo constante O(1). Em JavaScript, utilizamos objetos literais e Maps para representar hashtables. Essa abstração facilita a implementação, melhora a organização do código e pode trazer melhorias de performance para a aplicação.
Como utilizar hashtables para verificação condicional?
Imagine o seguinte cenário, estamos trabalhando em uma API de um restaurante e precisamos retornar uma mensagem com base no status do pedido. Como você implementaria essa regra?
Pode ser que você faria o seguinte:
function getOrderStatusMessage(orderStatus) {
if (orderStatus === "pending") {
return "Seu pedido está em análise.";
} else if (orderStatus === "processing") {
return "Seu pedido está sendo preparado.";
} else if (orderStatus === "shipped") {
return "Seu pedido foi enviado.";
} else if (orderStatus === "delivered") {
return "Seu pedido foi entregue!";
} else if (orderStatus === "canceled") {
return "Seu pedido foi cancelado";
} else {
return "Status desconhecido";
};
}
Ou até mesmo usaria um Switch Case:
function getOrderStatusMessage(orderStatus) {
switch (orderStatus) {
case "pending":
return "Seu pedido está em análise.";
case "processing":
return "Seu pedido está sendo preparado.";
case "shipped":
return "Seu pedido foi enviado.";
case "delivered":
return "Seu pedido foi entregue!";
case "canceled":
return "Seu pedido foi cancelado.";
default:
return "Status desconhecido";
}
}
As duas implementações são válidas e em ambos os casos, a lógica é clara: comparamos o valor de orderStatus
e retornamos uma mensagem adequada. No entanto, é importante entender que, do ponto de vista operacional, tanto o if...else
quanto o switch
realizam suas verificações de forma sequencial na maioria dos cenários. Por exemplo:
- Ao executar a verificação, se o valor inicial corresponder à primeira condição, o tempo de execução será de O(1), garantindo um desempenho extremamente eficiente.
- Entretanto, se o valor corresponder à última condição, o algoritmo precisará percorrer todas as condições anteriores, tornando o tempo de execução O(n), menos eficiente.
Isso nos leva aos trade-offs comuns na programação. Em termos de complexidade, ambas as estruturas possuem uma complexidade O(n), ou seja, tempo linear. Isso significa que, conforme o número de condições (ou casos) aumenta, o tempo de execução também aumenta de forma proporcional, impactando a performance da aplicação.
Agora vamos analisar o mesmo cenário utilizando hashtable:
function getOrderStatusMessage(orderStatus) {
const orderStatusMessages = {
pending: "Seu pedido está em análise.",
processing: "Seu pedido está sendo preparado.",
shipped: "Seu pedido foi enviado.",
delivered: "Seu pedido foi entregue!",
canceled: "Seu pedido foi cancelado."
};
// Se a chave não existir, retorna "Status desconhecido"
return orderStatusMessages[orderStatus] || "Status desconhecido";
}
console.log(getOrderStatusMessage("canceled")); // Output: "Seu pedido foi cancelado."
Nesse exemplo, usamos a notação de colchetes para acessar dinamicamente o valor associado à chave orderStatus
. Se a chave não for encontrada, o operador lógico ||
garante um retorno padrão.
Você não concorda que a implementação se tornou muito mais limpa?
Por que Usar Hashtables?
Performance Consistente: A busca por um valor em uma hashtable é feita em tempo constante, independentemente do tamanho da estrutura
Código Mais Limpo: Ao substituir estruturas condicionais aninhadas por um mapeamento chave-valor, o código se torna mais legível e de fácil manutenção.
Escalabilidade: Alterações na lógica de mapeamento podem ser feitas de forma centralizada, sem a necessidade de modificar múltiplos blocos condicionais.
Exemplo Prático: Categorização de Produtos em um E-commerce
Vamos praticar mais o uso de hashtables com uma lógica mais complexa.
Imagine que estamos desenvolvendo uma API para um E-Commerce e precisamos categorizar os produtos cadastrados com base no preço. Suponha as seguintes regras de negócio:
- Premium: Preço acima de 100.
- Regular: Preço entre 50 e 100.
- Basic: Preço inferior a 50.
Abaixo, implemento essas regras utilizando objetos:
const product = {
name: "Escova de Cabelo",
price: 50,
};
function categorizeProduct(product) {
const categories = {
premium: {
from: 101,
to: Infinity,
},
regular: {
from: 50,
to: 100,
},
basic: {
from: 0,
to: 49,
},
};
const productCategory = Object.keys(categories).find((key) => {
const category = categories[key];
return product.price >= category.from && product.price <= category.to;
});
return {
...product,
category: productCategory ? productCategory : null,
};
}
console.log(categorizeProduct(product)); // Output: { name: 'Escova de Cabelo', price: 50, category: 'regular' }
Nesta implementação, criamos um objeto chamado categories
onde cada chave (como premium
, regular
e basic
) representa uma categoria. Cada uma dessas categorias está associada a um objeto que define o intervalo de preços (from
e to
) para aquela categoria. Utilizamos o método Object.keys(categories)
para obter um array com as chaves do objeto categories
. Assim, temos:
Object.keys(categories) // Output: ["premium", "regular", "basic"];
Em seguida, usamos o método find
para percorrer o array de chaves. Em cada iteração, armazenamos o objeto que define o intervalo de preços da respectiva chave na variável category
. Então, verificamos se o preço do produto se encaixa no intervalo definido para aquela categoria:
return product.price >= category.from && product.price <= category.to;
/*
Se 'product.price' for maior que 100, então "premium" será
retornado.
Caso o valor de 'product.price' esteja entre 50 e
100, a string "regular" será retornada.
E por fim, caso possua um valor abaixo de 50, "basic" será retornado pelo método 'find'
*/
Assim, a função find
retorna a chave que corresponde a categoria correta.
Por fim, retornamos um novo objeto que inclui todas as propriedades do produto original e adiciona a propriedade category
com a categoria encontrada. Caso nenhuma categoria seja encontrada, retornamos null
como valor padrão.
Conclusão
Espero que tenha ficado claro o benefício de utilizar objetos para verificação condicional em JavaScript. Essa abordagem oferece vantagens significativas para a sua aplicação, como:
- Desempenho: A busca direta por chave elimina a necessidade de múltiplas comparações.
- Legibilidade: O código fica mais simples, organizado e fácil de entender.
- Manutenção: Alterar ou adicionar regras é mais simples, pois tudo está centralizado em um único local.
Pratique essa técnica para que sua implementação se torne natural e intuitiva. Vale ressaltar que aprendi essa abordagem com o incrível Erick Wendel, no vídeo Você não precisa do Postman para testar sua API, o qual recomendo muito. Em breve, pretendo publicar um artigo aprofundado sobre esse conteúdo.
Se tiver alguma dúvida ou quiser deixar um feedback sobre este artigo, sinta-se à vontade para comentar no dev.to ou me enviar uma mensagem pelas redes sociais!
Top comments (0)