Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

if else em JavaScript: como escrever condições

O if não testa true, testa truthiness. Ordem do else if, o if sem chaves que engana, early return e o SyntaxError Unexpected token else, tudo executado.

Rodolfo Mori7 min de leitura

if é como o programa toma decisão: ele avalia uma expressão, e se o resultado for verdadeiro executa o bloco entre chaves. O else é o caminho de quem não passou no teste.

A parte que ninguém avisa é que o if não testa true — ele testa truthiness. Qualquer valor entra ali dentro, e o motor converte para booleano antes de decidir. É por isso que if (carrinho.itens) continua entrando mesmo com o carrinho vazio, e o bug fica invisível por semanas.

Os exemplos são todos de uma loja: frete, pedido, estoque. O mesmo domínio de variáveis em JavaScript.

O termo técnico para essa escolha é fluxo condicional. Em palavras simples, o programa faz uma pergunta, converte o resultado para booleano e executa apenas o caminho correspondente. A qualidade da pergunta decide a qualidade da decisão.

A catraca faz uma pergunta por vez

Uma catraca de evento pode perguntar “o ingresso é válido?” e liberar ou barrar a passagem. Se a regra pergunta apenas “existe um cartão?”, um cartão vazio ainda pode passar. O if age sobre a condição escrita, não sobre a intenção de quem programou. Com truthiness, o JavaScript também converte valores que não são true ou false antes de escolher o bloco.

Antes do primeiro exemplo, escreva a conversão booleana de cada valor usado na condição e escolha o ramo esperado. Depois confira a saída. Quando errar, teste o valor isolado com Boolean(...): isso revela a conversão responsável sem culpar o if inteiro.

js
const total = 250;

if (total >= 199) {
  console.log('Frete grátis');
} else {
  console.log('Frete: R$ 24,90');
}
Frete grátis

Entre os parênteses vai uma expressão — algo que produz um valor. total >= 199 produz true. O bloco do if roda; o do else é ignorado. Só um dos dois roda, sempre.

O if não testa true — testa truthiness

Aqui está o comportamento que decide metade dos bugs de condição em JavaScript:

js
const cupom = '';
const observacao = '   ';
const itens = [];
const desconto = 0;

if (cupom) console.log('cupom aplicado');
if (observacao) console.log('tem observação');
if (itens) console.log('tem itens');
if (desconto) console.log('tem desconto');

console.log('fim');
tem observação tem itens fim

Leia a saída com calma. cupom vazio não entrou, mas observacao com três espaços entrou — espaço é caractere. E o pior: itens entrou com o array vazio. Um array vazio é um objeto, e todo objeto é truthy.

A lista de valores falsy é fechada e tem oito itens: false, 0, -0, 0n, '', null, undefined e NaN. Tudo o mais é truthy — incluindo [], {}, a string '0' e a string 'false'. Cada conversão está executada em truthy e falsy em JavaScript.

valor if (valor) entra? o que você provavelmente queria
'' não valor.trim() !== ''
' ' sim valor.trim() !== ''
0 não valor > 0 ou valor !== undefined
[] sim valor.length > 0
{} sim Object.keys(valor).length > 0
null / undefined não valor != null
NaN não Number.isFinite(valor)

A correção é sempre a mesma: teste a pergunta de verdade, não a existência do valor.

js
const pedido = { cliente: 'Ana', itens: [], desconto: 0 };

console.log(Boolean(pedido.itens));
console.log(pedido.itens.length > 0);
console.log(Boolean(pedido.desconto));
console.log(pedido.desconto > 0);
true false false false

Boolean(pedido.itens)true porque existe um array. pedido.itens.length > 0false porque não existe item nenhum. As duas perguntas são diferentes, e só a segunda é sobre o carrinho.

else if: a ordem das perguntas é o algoritmo

Encadear condições parece inofensivo até você errar a ordem. A loja cobra frete por faixa de valor:

js
function faixaDeFrete(total) {
  if (total >= 49) {
    return 'R$ 14,90';
  } else if (total >= 99) {
    return 'R$ 9,90';
  } else if (total >= 199) {
    return 'grátis';
  }
  return 'R$ 24,90';
}

console.log(faixaDeFrete(250));
console.log(faixaDeFrete(120));
console.log(faixaDeFrete(60));
console.log(faixaDeFrete(30));
R$ 14,90 R$ 14,90 R$ 14,90 R$ 24,90

Pedido de R$ 250 pagando frete. A cadeia para na primeira condição verdadeira, e 250 >= 49 já é verdade — as outras duas nunca são consultadas. Nada quebra, nenhum erro aparece; a loja só cobra errado.

A ordem certa vai da faixa mais restritiva para a mais ampla:

js
function faixaDeFrete(total) {
  if (total >= 199) {
    return 'grátis';
  } else if (total >= 99) {
    return 'R$ 9,90';
  } else if (total >= 49) {
    return 'R$ 14,90';
  }
  return 'R$ 24,90';
}

console.log(faixaDeFrete(250));
console.log(faixaDeFrete(120));
console.log(faixaDeFrete(60));
console.log(faixaDeFrete(30));
grátis R$ 9,90 R$ 14,90 R$ 24,90

Regra prática para faixas numéricas: do maior para o menor, ou do menor para o maior — mas nunca embaralhado. Se a cadeia tem mais de três else if, o switch case e a tabela de faixas costumam ler melhor que a escada.

O if sem chaves só leva a próxima instrução

A linguagem permite escrever if sem chaves. O bloco vira uma única instrução — e é aqui que a indentação mente para você:

js
const itens = [{ nome: 'Mouse sem fio', preco: 89.9 }];
const total = itens.reduce((soma, item) => soma + item.preco, 0);

let frete = 24.9;
let etiqueta = 'frete padrão';

if (total >= 199)
  frete = 0;
  etiqueta = 'frete grátis';

console.log({ total, frete, etiqueta });
{ total: 89.9, frete: 24.9, etiqueta: 'frete grátis' }

O total é R$ 89,90. O frete continuou R$ 24,90 — correto. E a etiqueta na tela diz “frete grátis”. A linha etiqueta = ... está indentada como se pertencesse ao if, mas não pertence: ela roda sempre.

Esse bug tem uma característica cruel — ele nasce numa segunda edição. Alguém escreveu o if de uma linha só, funcionando; meses depois outra pessoa acrescentou a segunda linha embaixo, alinhada, e o Prettier manteve o alinhamento sem reclamar. Escreva chaves sempre.

Early return: o padrão que apaga a escada de else

Validar entrada com if aninhado produz aquele código que vai andando para a direita:

js
function resumirPedido(pedido) {
  if (pedido) {
    if (Array.isArray(pedido.itens) && pedido.itens.length > 0) {
      if (pedido.cliente) {
        const total = pedido.itens.reduce((soma, item) => soma + item.preco, 0);
        return `${pedido.cliente}: R$ ${total.toFixed(2)}`;
      } else {
        return 'pedido sem cliente';
      }
    } else {
      return 'carrinho vazio';
    }
  } else {
    return 'pedido inexistente';
  }
}

console.log(resumirPedido({ cliente: 'Ana', itens: [{ preco: 289.9 }] }));
console.log(resumirPedido({ cliente: 'Bruno', itens: [] }));
console.log(resumirPedido(null));
Ana: R$ 289.90 carrinho vazio pedido inexistente

Funciona. Mas o caminho feliz — a linha que realmente calcula o total — está enterrado no terceiro nível, e o else que lhe corresponde está vinte linhas abaixo. Agora a mesma função com early return: cada caso ruim sai na porta, e o que sobra é o caso bom.

js
function resumirPedido(pedido) {
  if (!pedido) return 'pedido inexistente';
  if (!Array.isArray(pedido.itens) || pedido.itens.length === 0) return 'carrinho vazio';
  if (!pedido.cliente) return 'pedido sem cliente';

  const total = pedido.itens.reduce((soma, item) => soma + item.preco, 0);
  return `${pedido.cliente}: R$ ${total.toFixed(2)}`;
}

console.log(resumirPedido({ cliente: 'Ana', itens: [{ preco: 289.9 }] }));
console.log(resumirPedido({ cliente: 'Bruno', itens: [] }));
console.log(resumirPedido(null));
Ana: R$ 289.90 carrinho vazio pedido inexistente

Mesma saída, zero else, zero aninhamento. As três primeiras linhas são as cláusulas de guarda: leem como uma lista de pré-condições, e quem chega na quarta linha sabe que pedido, pedido.itens e pedido.cliente existem.

Esse padrão também é a defesa mais barata contra o TypeError: Cannot read properties of undefined: a guarda barra o undefined antes que alguém tente ler .length dele.

== dentro do if é uma armadilha a mais

O if já converte o valor da condição. Se você usar == dentro dele, ganha uma segunda conversão, agora entre os dois lados da comparação:

js
const quantidade = '0';

if (quantidade == 0) console.log('== considerou igual a zero');
if (quantidade === 0) console.log('=== considerou igual a zero');

console.log([] == false, '' == 0, null == undefined, null == false);
== considerou igual a zero true true true false

A string '0' — que é truthy — comparou igual ao número 0 com ==. E [] == falsetrue, embora if ([]) entre. Um array vazio é simultaneamente truthy e “igual a false”: as duas regras de conversão são diferentes, e tentar guardar as duas na cabeça é perda de tempo.

Erros comuns: SyntaxError: Unexpected token 'else'

Este é o erro que mais aparece na primeira semana. Um ponto e vírgula depois da chave de fechamento encerra o if — e aí o else fica órfão:

js
const total = 250;

if (total >= 199) {
  console.log('Frete grátis');
};
else {
  console.log('Frete: R$ 24,90');
}
file:///private/tmp/loja/i09.mjs:6 else { ^^^^

SyntaxError: Unexpected token ‘else’ at compileSourceTextModule (node:internal/modules/esm/utils:318:16) at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:90:18) at #translate (node:internal/modules/esm/loader:435:20)

Node.js v24.16.0

Repare em duas coisas. Primeiro: nenhuma linha rodou. SyntaxError acontece na compilação do módulo, antes da primeira instrução — o console.log da linha 4 nunca existiu. Segundo: o Node aponta a linha 6, a do else, mas o defeito está na linha 5. O motor só percebe o problema quando chega no token que não cabe.

As três causas, em ordem de frequência:

  • }; antes do else — bloco fechado com ponto e vírgula, como no exemplo;
  • else sem if acima, geralmente sobra de um refactor que apagou a condição;
  • uma chave a mais no bloco do if, que fecha a função inteira antes da hora.

Quando bater esse erro, olhe a linha anterior à que o Node apontou.

Quando o if já não é a ferramenta

O if é instrução: ele executa, não devolve valor. Três situações em que outra coisa cabe melhor:

  • Escolher entre dois valores para atribuir ou interpolar numa string. É o caso do operador ternário, que é expressão e por isso cabe dentro de um template literal.
  • Comparar a mesma variável contra muitos valores fixos — status de pedido, forma de pagamento, sigla de estado. Aí a leitura melhora com switch ou com um objeto de consulta.
  • Valor padrão quando algo é null ou undefined. const cupom = entrada ?? 'SEMCUPOM' diz em uma linha o que um if diz em quatro, e não confunde string vazia com ausência.

A próxima lição da trilha de JavaScript é exatamente o ternário. Se quiser ver onde as condicionais entram no percurso inteiro, o guia completo de JavaScript mostra a ordem de estudo.

Prefere aprender em vídeo?

Tem uma aula sobre este assunto no nosso canal.

Ver todos os vídeos do canal
  • if
  • else
  • condicionais
  • truthiness
  • early return

Perguntas frequentes

Preciso sempre escrever o else?
Não. Quando o bloco do if termina em return, throw, break ou continue, o else vira ruído — o código depois do if já é o caminho alternativo. Escrever else nesse caso só empurra o resto da função para dentro de mais um nível.
Posso usar if sem chaves?
A linguagem permite, e é justamente por isso que dá problema. Sem chaves o if leva só a próxima instrução; a linha seguinte roda sempre. Em código de time, chaves em tudo — o custo são dois caracteres.
Por que if (0) e if ('') não entram?
Porque o if converte o valor para booleano antes de decidir. Os oito valores falsy são false, 0, -0, 0n, string vazia, null, undefined e NaN. Todo o resto é truthy, inclusive array vazio, objeto vazio e a string "0".
Dá para comparar dois objetos dentro de um if?
Dá, mas quase nunca é o que você quer. Comparar objetos com === compara a referência, não o conteúdo: dois objetos com os mesmos campos dão false. Compare os campos que importam, ou uma chave como o id do pedido.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Node 24.16.0, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. MDN — if...else — developer.mozilla.org
  2. MDN — Truthy — developer.mozilla.org

Continue por aqui