DEV Community

Vinicius Bavosa
Vinicius Bavosa

Posted on

2 1

Deixe o If...Else de lado! Use Hashtable em JavaScript

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.

Objeto javascript

Um objeto javascript

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";
 };

}
Enter fullscreen mode Exit fullscreen mode

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";
  }
}
Enter fullscreen mode Exit fullscreen mode

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."
Enter fullscreen mode Exit fullscreen mode

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' }
Enter fullscreen mode Exit fullscreen mode

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"];
Enter fullscreen mode Exit fullscreen mode

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'  
*/
Enter fullscreen mode Exit fullscreen mode

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)

Visualizing Promises and Async/Await 🤯

async await

☝️ Check out this all-time classic DEV post

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay