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

Mar 20, 2025 - 22:25
 0
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";
 };

}

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!