Decisões com condicionais
por Briar WestbrookEntenda o conceito
Condicionais fazem o programa escolher um caminho. O if executa um bloco só quando a condição entre parênteses é verdadeira; o else cobre o caso contrário, e o else if encadeia novas condições. Elas são testadas de cima para baixo e apenas o primeiro bloco verdadeiro roda, por isso a ordem das faixas importa.
As condições costumam vir de comparações (===, !==, <, >=) combinadas com operadores lógicos: && (e) exige que tudo seja verdadeiro, || (ou) basta que uma parte seja, e ! inverte o resultado. Prefira sempre === e !==, que comparam valor e tipo, ao ==, que converte os tipos antes de comparar.
Quando um mesmo valor é comparado com várias opções fixas, o switch fica mais legível que uma fila de else if; cada case termina com break. Para escolher entre dois valores numa expressão curta, existe o operador ternário condição ? a : b. E todo valor tem um lado verdadeiro ou falso: 0, '', null, undefined, NaN e false são falsy, o resto é truthy. O operador ?? dá um valor padrão só para null e undefined.
- Numa cadeia
if/else if/else, só o primeiro bloco verdadeiro é executado; ordene as faixas do limite mais alto para o mais baixo (ou o contrário, com cuidado). - Use
===e!==nas comparações:0 == ''dátrue, mas0 === ''dáfalse. &&exige todas as condições,||exige pelo menos uma e!inverte um boolean.- No
switch, esquecer obreakfaz a execução seguir para o próximocase;defaulttrata os valores que não casaram com nenhum. 0,'',null,undefined,NaNefalsesão falsy; para valor padrão sem perder o0, use??em vez de||.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Faixas de frete da loja com if, else if e else
// Frete da loja decidido por faixas de valor com if, else if e else.
const subtotal = 149.9;
const cidade = 'Campinas';
console.log(`Subtotal do carrinho: R$ ${subtotal.toFixed(2)}`);
// As condições são testadas de cima para baixo; só o primeiro bloco verdadeiro roda
let frete;
if (subtotal >= 200) {
frete = 0;
} else if (subtotal >= 100) {
frete = 9.9;
} else {
frete = 19.9;
}
console.log(`Frete: R$ ${frete.toFixed(2)}`);
// Um if sozinho, sem else: só faz algo quando a condição é verdadeira
if (frete === 0) {
console.log('Parabéns, você ganhou frete grátis!');
}
// Quanto falta para a próxima faixa, calculado só quando faz sentido
if (subtotal < 200) {
const falta = 200 - subtotal;
console.log(`Faltam R$ ${falta.toFixed(2)} para o frete grátis.`);
}
// Comparação de texto com === diferencia maiúsculas de minúsculas
if (cidade === 'Campinas') {
console.log('Entrega no mesmo dia disponível.');
} else {
console.log('Entrega em até 3 dias úteis.');
}
A cadeia if / else if / else define o frete por faixas. Como as condições são testadas de cima para baixo, um subtotal de 149.9 falha em >= 200, passa em >= 100 e para ali: o else final nem é avaliado. Por isso a faixa mais alta vem primeiro; se >= 100 estivesse no topo, uma compra de R$ 250 também cairia nela.
Os if seguintes não têm else: eles só imprimem algo quando a condição é verdadeira. O último compara textos com ===, que exige igualdade exata, inclusive de maiúsculas e minúsculas.
02Regras de empréstimo da biblioteca com switch e operadores lógicos
// Regras de empréstimo da biblioteca com operadores lógicos e switch.
const tipoLeitor = 'professor';
const livrosEmMaos = 2;
const temAtraso = false;
const livroDeConsulta = false;
// switch compara o valor com cada case usando ===
let limite;
let prazoDias;
switch (tipoLeitor) {
case 'aluno':
limite = 3;
prazoDias = 7;
break; // sem o break, o código continuaria no próximo case
case 'professor':
limite = 5;
prazoDias = 15;
break;
default:
limite = 1;
prazoDias = 5;
}
console.log(`Leitor: ${tipoLeitor} | limite: ${limite} | prazo: ${prazoDias} dias`);
// && exige que todas as condições sejam verdadeiras; ! inverte um boolean
const podeEmprestar = !temAtraso && livrosEmMaos < limite && !livroDeConsulta;
console.log('Pode emprestar?', podeEmprestar);
if (podeEmprestar) {
console.log(`Empréstimo liberado. Devolva em ${prazoDias} dias.`);
} else if (temAtraso || livroDeConsulta) {
// || basta que uma das condições seja verdadeira
console.log('Empréstimo negado: atraso pendente ou livro só para consulta.');
} else {
console.log('Empréstimo negado: limite de livros atingido.');
}
O switch compara tipoLeitor com cada case usando === e define limite e prazo de uma vez. O break encerra o switch; sem ele, o código do próximo case também rodaria. O default cobre qualquer tipo de leitor não previsto, como um visitante.
A constante podeEmprestar junta três condições com &&: o leitor não pode ter atraso (!temAtraso), precisa estar abaixo do limite e o livro não pode ser de consulta. No else if, o || basta que um dos impedimentos seja verdadeiro para explicar a recusa.
03Ternário, truthy/falsy e ?? numa receita
// Ternário, valores truthy/falsy e ?? ao montar uma receita.
const receita = 'Panqueca';
const porcoesPedidas = 0; // o usuário digitou zero de propósito
const observacao = ''; // campo deixado em branco
let tempoPreparo; // ainda não informado
// O ternário escolhe entre dois valores: condição ? seVerdadeiro : seFalso
const rotulo = porcoesPedidas === 1 ? 'porção' : 'porções';
console.log(`${receita}: ${porcoesPedidas} ${rotulo}`);
// 0, '', null, undefined, NaN e false são falsy: um if os trata como falso
if (observacao) {
console.log('Observação:', observacao);
} else {
console.log('Sem observações.');
}
// || troca qualquer valor falsy, inclusive o 0 que foi digitado de propósito
const porcoesComOu = porcoesPedidas || 4;
// ?? troca só null e undefined, preservando o 0
const porcoesComNulo = porcoesPedidas ?? 4;
console.log('Com ||:', porcoesComOu, '| com ??:', porcoesComNulo);
// ?? é o jeito certo de dar um valor padrão a algo ainda não informado
const tempo = tempoPreparo ?? 20;
console.log(`Tempo de preparo: ${tempo} minutos`);
// Ternário dentro do template literal para uma mensagem curta
const dificuldade = tempo > 30 ? 'trabalhosa' : 'rápida';
console.log(`Receita ${dificuldade} para o lanche.`);
O ternário escolhe entre 'porção' e 'porções' numa única expressão, sem precisar de let e de um if completo. Em seguida, if (observacao) usa a string diretamente como condição: a string vazia é falsy, então o else é executado.
A comparação entre || e ?? é o ponto principal. Como 0 é falsy, porcoesPedidas || 4 descarta o zero digitado e devolve 4; já ?? só troca null e undefined, então preserva o 0. Para tempoPreparo, que ainda é undefined, o ?? aplica o padrão de 20 minutos.
Agora é com você
Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.
01Conceito no boletimFácil
A aluna Bia terminou o bimestre com média 8.6. Converta a média em conceito (A a partir de 9, B a partir de 7, C a partir de 5 e D abaixo disso) e informe se ela está aprovada (média a partir de 6) ou em recuperação.
- Calcular o conceito com uma única cadeia
if/else if/else. - Escolher a situação (
'aprovada'ou'em recuperação') com o operador ternário. - Imprimir aluna, média, conceito e situação em linhas separadas.
- A saída deve ser idêntica à saída esperada.
const aluna = 'Bia';
const media = 8.6;
let conceito;
// escolha o conceito com if / else if / else
// escolha a situação com o ternário e imprima o boletim
Aluna: Bia
Média: 8.6
Conceito: B
Situação: aprovada
Ver dica
Comece testando o limite mais alto: se a média for pelo menos 9, nenhuma outra faixa precisa ser olhada.
Ver resposta
// Conceito e situação de uma aluna a partir da média final
const aluna = 'Bia';
const media = 8.6;
// Do maior limite para o menor: a primeira condição verdadeira decide
let conceito;
if (media >= 9) {
conceito = 'A';
} else if (media >= 7) {
conceito = 'B';
} else if (media >= 5) {
conceito = 'C';
} else {
conceito = 'D';
}
// Ternário para escolher entre duas palavras
const situacao = media >= 6 ? 'aprovada' : 'em recuperação';
console.log(`Aluna: ${aluna}`);
console.log(`Média: ${media}`);
console.log(`Conceito: ${conceito}`);
console.log(`Situação: ${situacao}`);
Passo a passo
let conceito;declara a variável antes da cadeia, porque cada bloco vai atribuir um valor diferente a ela; comconstisso não seria possível.- O primeiro
iftestamedia >= 9. Para 8.6 a condição é falsa, então o JavaScript passa para oelse ifseguinte. media >= 7é verdadeiro econceitorecebe'B'. A partir daqui o resto da cadeia é ignorado, mesmo quemedia >= 5também seja verdadeiro.- O
elsefinal pega qualquer média abaixo de 5, sem precisar de uma condição própria. media >= 6 ? 'aprovada' : 'em recuperação'escolhe uma das duas palavras numa só expressão e guarda o resultado em umaconst.- Os quatro
console.logmontam o boletim com template literals.
Por que funciona
As faixas estão em ordem decrescente, então a primeira condição verdadeira é exatamente a faixa da média. Cada else if só é avaliado quando todos os anteriores falharam, o que dispensa escrever media >= 7 && media < 9. O ternário é a ferramenta certa para a situação porque há apenas duas saídas e o resultado é um valor, não um bloco de instruções.
Erros comuns
- Ordem invertida das faixas: começar com
if (media >= 5)faz toda média de 5 para cima receber'C', porque a cadeia para na primeira condição verdadeira. Teste do maior limite para o menor. - Vários
ifindependentes: trocar oselse ifporifsoltos faz o 8.6 entrar em>= 7e depois em>= 5, terminando com'C'. Useelse ifpara que só um bloco rode. - Usar
=na condição:if (media = 9)atribui 9 à variável em vez de comparar (e, comconst, geraTypeError). Para comparar use>=,===e afins. - Declarar
conceitodentro do bloco:if (...) { let conceito = 'A'; }cria uma variável que só existe dentro das chaves, e oconsole.logfinal geraReferenceError.
Outra forma de resolver
O conceito também sai de ternários encadeados: const conceito = media >= 9 ? 'A' : media >= 7 ? 'B' : media >= 5 ? 'C' : 'D';. Fica em uma linha e permite usar const, mas com mais de duas ou três faixas a cadeia de if é mais fácil de ler e de alterar.
Saída esperada
Aluna: Bia
Média: 8.6
Conceito: B
Situação: aprovada
02Efeito do dado no tabuleiroMédio
Num jogo de tabuleiro, a peça está na casa 15 e o dado deu 4. Use um switch para definir o efeito do dado (1 e 2: caminho normal; 3: carta de sorte; 4 e 5: vento a favor, com 2 casas extras; 6: jogue de novo; outro valor: jogada inválida) e diga se a peça chegou à casa 20.
- Usar
switchcomcaseagrupados para 1 e 2 e para 4 e 5, cada grupo terminando combreak. - Tratar valores fora de 1 a 6 no
default, com avanço 0. - Usar
if/elsepara anunciar a vitória ou quantas casas faltam até a casa 20. - A saída deve ser idêntica à saída esperada.
const dado = 4;
const posicaoAtual = 15;
const casaFinal = 20;
let avanco = dado;
let efeito;
// defina efeito e avanco com switch
// calcule a nova posição e verifique se chegou ao fim
Dado: 4
Efeito: vento a favor, +2 casas
Posição: 15 -> 21
Chegou ao fim do tabuleiro: vitória!
Ver dica
Dois case seguidos sem nada entre eles levam ao mesmo bloco de código.
Ver resposta
// Efeito do dado em uma partida de tabuleiro
const dado = 4;
const posicaoAtual = 15;
const casaFinal = 20;
let avanco = dado;
let efeito;
switch (dado) {
case 1:
case 2:
efeito = 'caminho normal';
break;
case 3:
efeito = 'tire uma carta de sorte';
break;
case 4: // 4 e 5 compartilham o mesmo bloco
case 5:
efeito = 'vento a favor, +2 casas';
avanco = dado + 2;
break;
case 6:
efeito = 'jogue de novo';
break;
default:
efeito = 'valor inválido, a jogada não conta';
avanco = 0;
}
const novaPosicao = posicaoAtual + avanco;
console.log(`Dado: ${dado}`);
console.log(`Efeito: ${efeito}`);
console.log(`Posição: ${posicaoAtual} -> ${novaPosicao}`);
if (novaPosicao >= casaFinal) {
console.log('Chegou ao fim do tabuleiro: vitória!');
} else {
console.log(`Faltam ${casaFinal - novaPosicao} casas.`);
}
Passo a passo
avancocomeça igual ao valor do dado, porque na maioria dos casos a peça anda exatamente isso; só ocasedo vento a favor e odefaultmudam esse valor.case 1:seguido decase 2:sem código entre eles agrupa os dois valores: qualquer um deles executa o mesmo bloco.case 4:ecase 5:fazem o mesmo agrupamento e somam 2 casas ao avanço. Com o dado 4, a peça anda 6.- Cada grupo termina com
break, que encerra oswitche impede que o bloco seguinte também rode. - O
defaultrecebe qualquer valor que não casou com nenhumcase(um 7 vindo de um bug, por exemplo) e zera o avanço. - Depois do
switch, a nova posição é calculada e oif/elsedecide entre a mensagem de vitória e a contagem de casas restantes.
Por que funciona
O switch compara dado com cada case usando === e começa a executar a partir do primeiro que casar, seguindo até encontrar um break. É esse comportamento que permite agrupar valores e, ao mesmo tempo, exige o break no fim de cada grupo. Como o valor é um número com poucas opções fixas, o switch deixa a tabela de efeitos mais clara que uma sequência de else if.
Erros comuns
- Esquecer o
break: sem obreakdepois do vento a favor, a execução cai nocase 6eefeitotermina como'jogue de novo'. Feche cada grupo combreak. - Comparar com texto:
case '4':nunca casa com o número4, porque oswitchusa===. Mantenha o mesmo tipo dos dois lados. - Somar o extra no lugar errado: escrever
avanco = 2em vez deavanco = dado + 2faz a peça andar só 2 casas. O extra é somado ao valor do dado. - Testar só a igualdade com a casa final:
if (novaPosicao === casaFinal)falha quando a peça passa da casa 20, como aqui (21). Use>=.
Outra forma de resolver
Uma cadeia de if com || resolve o mesmo problema: if (dado === 4 || dado === 5) { ... } else if (dado === 6) { ... }. Ela é preferível quando as condições envolvem faixas ou várias variáveis; para um único valor comparado com opções fixas, o switch fica mais organizado.
Saída esperada
Dado: 4
Efeito: vento a favor, +2 casas
Posição: 15 -> 21
Chegou ao fim do tabuleiro: vitória!
03Fechamento de pedido com cupomDesafio
Feche um pedido de R$ 180 com o cupom 'PRIMEIRA', de um cliente que já comprou antes e vai pagar no Pix. Aplique as regras do cupom com switch, o frete (grátis pelo cupom ou a partir de R$ 200, senão R$ 15) e 5% de desconto no Pix sobre o valor já com o cupom.
- Tratar os cupons
'PRIMEIRA'(15% só para cliente novo, senão uma mensagem de recusa),'DEZOFF'(R$ 10 a partir de R$ 50),'FRETEGRATIS'e cupom inexistente comswitchedefault. - Calcular o frete com uma única expressão que combine
||e o operador ternário. - Calcular o desconto do Pix com o operador ternário e exibir todos os valores com duas casas decimais.
- A saída deve ser idêntica à saída esperada.
const subtotal = 180;
const cupom = 'PRIMEIRA';
const clienteNovo = false;
const pagamentoPix = true;
let descontoCupom = 0;
let freteGratis = false;
// aplique o cupom com switch, depois calcule frete, Pix e total
Cupom PRIMEIRA recusado: vale só para a primeira compra.
Subtotal: R$ 180.00
Desconto do cupom: R$ 0.00
Desconto Pix: R$ 9.00
Frete: R$ 15.00
Total: R$ 186.00
Ver dica
Um if pode ficar dentro de um case: o cupom é reconhecido pelo switch, mas só vale se uma segunda condição também for verdadeira.
Ver resposta
// Fechamento de um pedido com cupom, frete e desconto no Pix
const subtotal = 180;
const cupom = 'PRIMEIRA';
const clienteNovo = false;
const pagamentoPix = true;
let descontoCupom = 0;
let freteGratis = false;
// Cada cupom tem uma regra própria
switch (cupom) {
case 'PRIMEIRA':
if (clienteNovo) {
descontoCupom = subtotal * 0.15;
} else {
console.log('Cupom PRIMEIRA recusado: vale só para a primeira compra.');
}
break;
case 'DEZOFF':
descontoCupom = subtotal >= 50 ? 10 : 0;
break;
case 'FRETEGRATIS':
freteGratis = true;
break;
default:
console.log(`Cupom ${cupom} não existe.`);
}
// Frete zero pelo cupom ou por compra acima de R$ 200
const frete = freteGratis || subtotal >= 200 ? 0 : 15;
// O Pix dá 5% sobre o valor já com o desconto do cupom
const descontoPix = pagamentoPix ? (subtotal - descontoCupom) * 0.05 : 0;
const total = subtotal - descontoCupom - descontoPix + frete;
console.log(`Subtotal: R$ ${subtotal.toFixed(2)}`);
console.log(`Desconto do cupom: R$ ${descontoCupom.toFixed(2)}`);
console.log(`Desconto Pix: R$ ${descontoPix.toFixed(2)}`);
console.log(`Frete: R$ ${frete.toFixed(2)}`);
console.log(`Total: R$ ${total.toFixed(2)}`);
Passo a passo
descontoCupomcomeça em0efreteGratisemfalse: são os valores para quando nenhum cupom se aplica, e cadacasesó altera o que lhe diz respeito.- No
case 'PRIMEIRA', umif/elseinterno confere se o cliente é novo. ComoclienteNovoéfalse, o desconto continua zero e a mensagem de recusa é impressa logo nesse momento, antes do resumo. 'DEZOFF'usa um ternário para dar R$ 10 só quando o subtotal atinge R$ 50, e'FRETEGRATIS'apenas liga a variávelfreteGratis.- O
defaultavisa sobre qualquer código que não existe, sem mexer nos valores iniciais. freteGratis || subtotal >= 200 ? 0 : 15primeiro resolve o||(que tem precedência maior que o ternário) e depois escolhe o frete: aqui as duas partes são falsas, então o frete é 15.- O desconto do Pix é calculado sobre
subtotal - descontoCupom, como pede o enunciado: 5% de 180 dá 9. - O total soma tudo e
toFixed(2)formata cada valor com duas casas decimais.
Por que funciona
O switch separa as regras por cupom, e cada regra pode ter suas próprias condições, como o if dentro de 'PRIMEIRA'. Os valores iniciais garantem que, quando um cupom é recusado ou não existe, as contas seguintes continuam corretas sem precisar de ramos extras. Frete e Pix têm só duas saídas cada, por isso cabem em ternários, e o || junta numa única condição os dois motivos que zeram o frete.
Erros comuns
- Aplicar o desconto sem checar o cliente: escrever só
descontoCupom = subtotal * 0.15;nocase 'PRIMEIRA'dá R$ 27 de desconto a quem já comprou antes. A regra extra precisa de umifdentro docase. - Calcular o Pix sobre o subtotal cheio:
subtotal * 0.05ignora o cupom; com um cupom válido, o desconto sairia maior do que deveria. Use(subtotal - descontoCupom) * 0.05. - Parênteses no lugar errado:
freteGratis || (subtotal >= 200 ? 0 : 15)funciona com o cupom comum, mas com'FRETEGRATIS'o frete viratrue, o total soma 1 em vez de 0 efrete.toFixed(2)geraTypeError. Se quiser deixar a ordem explícita, escreva(freteGratis || subtotal >= 200) ? 0 : 15. - Esquecer o
breaknocase 'DEZOFF': a execução segue para'FRETEGRATIS'e o cliente ganha frete grátis sem ter direito.
Outra forma de resolver
Uma cadeia if (cupom === 'PRIMEIRA' && clienteNovo) { ... } else if (cupom === 'PRIMEIRA') { ... } else if (cupom === 'DEZOFF') { ... } produz o mesmo resultado sem switch. Ela é útil quando as regras dependem de várias variáveis ao mesmo tempo, mas repete o nome do cupom em várias condições; com muitos cupons, o switch deixa cada regra no seu próprio bloco e fica mais fácil de manter.
Saída esperada
Cupom PRIMEIRA recusado: vale só para a primeira compra.
Subtotal: R$ 180.00
Desconto do cupom: R$ 0.00
Desconto Pix: R$ 9.00
Frete: R$ 15.00
Total: R$ 186.00