Dia 5 — Condicionais

Informatica · Conteudo · publicado em 05/10/2026
Dia 5 de 13

Condicionais

Aula 1

if, else if e else

if, else if e else

if executa um bloco de código quando a condição é verdadeira. A condição não

precisa ser booleana: o JavaScript testa se o valor é truthy, e qualquer um dos

sete valores falsy conta como falso.

if (idade >= 18) {
  console.log('maior de idade');
}

else é o caminho de quando a condição é falsa, e else if é um meio-termo

quando existem mais de dois caminhos. A ordem importa: o JavaScript testa de cima

para baixo e executa o primeiro que for verdadeiro, ignorando o resto.

if (total === 0) {
  console.log('vazio');
} else if (total < 10) {
  console.log('poucos');
} else {
  console.log('muitos');
}

O exemplo roda essa cadeia com total valendo 7 e imprime uma linha só:

poucos itens: 7. Uma linha, não três — e é esse o comportamento do else if.

A primeira condição falhou, a segunda passou, e a terceira nunca foi olhada. Com

total em 900 a mesma cadeia imprimiria a linha do else, e com 0 a do

primeiro.

A função faixa no fim do exemplo é a mesma ideia com quatro caminhos, e o

console imprime o resultado das quatro de uma vez:

faixa: vazio | poucos | muitos | demais. Ela roda sobre [0, 7, 42, 900], e

cada número cai num caminho diferente. É a forma que o app usa para classificar

quantidade sem switch e sem else grudado.

As chaves não são detalhe de escrita

O if sem chaves é o defeito mais silencioso. O bloco é o que está entre { }, e as chaves são obrigatórias quando há mais

de um comando. Sem elas, o JavaScript considera apenas a próxima instrução como

corpo:

// isso e um bloco so
if (total > 0)
  console.log('tem itens');
  console.log('esta linha roda sempre');   // nao esta dentro do if

O console.log do segundo está fora do if: a indentação sugerindo o contrário é

só visual. Esse é o bug mais silencioso de if sem chaves, porque o código roda e

o resultado sai errado. Escreva sempre as chaves.

As duas linhas do exemplo aparecem lado a lado, e é a ordem delas que denuncia o

problema: dentro do if vem primeiro, e `fora do if: roda sempre, a indentacao

aqui e so visual vem em seguida. Se a segunda linha estivesse dentro do if`,

ela sairia antes — porque o if imprime primeiro. A segunda linha saiu depois

porque ninguém a escolheu: ela está no nível do if, e o if é só uma

instrução.

A mesma demonstração do parágrafo sobre condição não booleana está no exemplo, e

o console mostra exatamente um dos dois lados rodando. if ('' && 'ana') não

imprime nada: a string vazia é falsy e o && devolve '', que é falsy. Na

linha seguinte if ([0]) imprime array vazio e truthy, este bloco roda — o

array [0] tem um item, mas mesmo [] seria truthy, porque objeto é truthy. A

ausência de uma das duas linhas no terminal é parte da prova.

Condição aninhada

Aninhar é colocar um if dentro do outro. Funciona, e em geral é sinal de que

o teste pode ser reescrito com uma condição só, usando && e ||:

// aninhado
if (idade >= 18) {
  if (documento === true) {
    console.log('pode retirar');
  }
}

// mesma regra em uma condicao so
if (idade >= 18 && documento === true) {
  console.log('pode retirar');
}

A cadeia de if é a forma de tratar vários casos do mesmo dado. O early return é o nome técnico do caminho mais limpo, quando o valor tem

nomes definidos — sair

da função assim que a condição decide o resultado:

function mensagemDoStatus(status) {
  if (status === 'pendente') return 'ainda falta';
  if (status === 'concluida') return 'pronto';
  return 'desconhecido';
}

Cada if com return elimina um nível de indentação. É o motivo de a forma ser

preferida mesmo quando o aninhamento "caberia": a função tem uma saída por vez e

não existe else grudado.

O exemplo chama mensagemDoStatus com os três valores de uma vez e imprime

status: ainda falta | pronto | desconhecido. Cada nome saiu de um if

diferente, e o terceiro saiu do return que sobrou no fim — que é o que acontece

com qualquer status que a função não conhece. Sem esse return final, o

terceiro valor devolveria undefined, e o join escreveria a palavra

undefined no meio da linha.

O aninhado e o && também aparecem lado a lado, com a mesma resposta:

aninhado: pode retirar e depois com &&: pode retirar. Duas linhas, mesmo

resultado, formas diferentes. O && ganha quando os dois testes são sobre o

mesmo dado; o aninhamento continua sendo o certo quando o segundo teste só faz

sentido depois que o primeiro passou.

A indentação conta para quem lê

Indentação é o espaço no começo da linha que mostra o que está dentro de quê. O

JavaScript ignora os espaços — o que define o bloco são as chaves — mas quem lê o

código depende do recuo para entender a estrutura. Um arquivo com indentação

inconsistente não está errado para o JavaScript e está errado para quem precisa

entender o if às onze da noite.

O exemplo é a prova de que o JavaScript ignora o recuo: a linha

fora do if: roda sempre, a indentacao aqui e so visual está alinhada com o

if e não com o corpo, e o console a mostra como quem é — uma linha que sempre

roda. Se a indentação decidisse o bloco, essa linha nunca sairia.

Exemplo

// if, else if e else. O exemplo mostra a cadeia de condicao, o bloco com
// chaves e o retorno antecipado.
const total = 7;

if (total === 0) {
  console.log('vazio');
} else if (total < 10) {
  console.log('poucos itens:', total);
} else {
  console.log('muitos itens:', total);
}

// a condicao nao precisa ser booleana: o JavaScript testa truthy e falsy
if ('' && 'ana') {
  console.log('string vazia e falsy, este bloco nao roda');
}
if ([0]) {
  console.log('array vazio e truthy, este bloco roda');
}

// sem chaves, so a proxima instrucao e o corpo do if
if (total > 0)
  console.log('dentro do if');
  console.log('fora do if: roda sempre, a indentacao aqui e so visual');

// condicao aninhada
const idade = 20;
const documento = true;
if (idade >= 18) {
  if (documento === true) {
    console.log('aninhado: pode retirar');
  }
}
// a mesma regra, em uma condicao so
if (idade >= 18 && documento === true) {
  console.log('com &&: pode retirar');
}

// cadeia de if com retorno antecipado: uma saida por vez
function mensagemDoStatus(status) {
  if (status === 'pendente') return 'ainda falta';
  if (status === 'concluida') return 'pronto';
  return 'desconhecido';
}
console.log('status:', ['pendente', 'concluida', 'outro'].map(mensagemDoStatus).join(' | '));

// a funcao que classifica a quantidade, que e o que o app vai usar
function faixa(total) {
  if (total === 0) return 'vazio';
  else if (total < 10) return 'poucos';
  else if (total < 100) return 'muitos';
  else return 'demais';
}
console.log('faixa:', [0, 7, 42, 900].map(faixa).join(' | '));

Saída real

poucos itens: 7
array vazio e truthy, este bloco roda
dentro do if
fora do if: roda sempre, a indentacao aqui e so visual
aninhado: pode retirar
com &&: pode retirar
status: ainda falta | pronto | desconhecido
faixa: vazio | poucos | muitos | demais
Aula 2

Operador ternário e switch

Operador ternário e switch

O operador ternário é a condição escrita em uma expressão. São três partes na

ordem: a condição, o valor se verdadeiro, o valor se falso — separadas por ? e

:. Equivale a um if com else que devolve valor em vez de executar

comandos:

const situacao = total > 0 ? 'tem itens' : 'vazio';

O que define o ternário é ser expressão. Ele pode aparecer dentro de outra

expressão, coisa que o if não faz:

console.log(`${total} tarefa${total === 1 ? '' : 's'}`);

Essa linha é a razão de o ternário existir no React Native: montar o texto que

vai dentro do Text com plural, sem if espalhado pelo JSX.

O exemplo imprime as três formas do ternário, e a segunda é a que interessa:

plural dentro do texto: 3 tarefas. O ${total === 1 ? '' : 's'} devolveu

's', e o resultado é o texto montado inteiro — sem variável no meio, sem if

antes. A primeira linha, ternario: tem itens, é o ternário dos três campos

isolado; a terceira, ternario de true/false: sim, mostra o caso mais curto, em

que a condição já é comparação e os dois lados são palavras.

A armadilha do ternário aninhado

Ternário aninhado é permitido, mas fica ilegível rápido. Quando o valor tem mais

de dois nomes possíveis, o objeto de tradução é melhor — o switch logo abaixo

faz o mesmo com menos ruído:

const precos = { basico: 10, pro: 20 };
console.log(precos[plano]);

O exemplo usa essa forma e imprime preco do plano: 20: o objeto precos é a

tabela, e o plano é o índice. Com quatro planos, o ternário aninhado vira

quatro linhas de ? : dentro de ? :; com o objeto, vira quatro linhas de

chave e valor, e o console.log é o mesmo. O switch da seção seguinte faz o

mesmo serviço quando o valor tem casos que executam código, e não só devolvem

um valor.

switch: o caso com nome

switch compara um valor contra vários case. Cada case precisa terminar em

break. Sem ele a execução cai no caso seguinte — o termo é fallthrough:

switch (status) {
  case 'pendente':
    console.log('ainda falta');
    break;
  case 'concluida':
    console.log('pronto');
    break;
  default:
    console.log('desconhecido');
}

O default é o caminho de quando nenhum case casa, e cumpre o papel do else.

O teste do switch é comparação estrita (===), então '1' não casa com

1.

O fallthrough raramente é erro de digitação e sempre é uma pergunta: ele

funciona de verdade quando um caso compartilha a execução com o seguinte, e o

comentário dizendo isso é obrigatório:

switch (nivel) {
  case 1:
  case 2:
    console.log('iniciante');
    break;
}

Os dois case são o fallthrough proposital: nível 1 e nível 2 imprimem a mesma

coisa. Sem o break, um case que não acaba em comando cai no próximo — e é

assim que o bug aparece, quando alguém acrescenta um case no meio e não percebe

que o anterior não tem break.

O exemplo separa os dois fallthroughs em duas funções, porque eles não são o

mesmo defeito. descreverStatus usa break em todos os case e a linha sai

switch: ainda falta | pronto | desconhecido — três entradas, três saídas

diferentes. cairNoSeguinte não usa nenhum break, e com o número 2 o

console imprime fallthrough: doistres.

O resultado doistres é o ponto inteiro da demonstração. A entrada foi 2, e a

saída tem palavras de três casos: passou por 'um' (sem executar, porque o

case 1 não casou), por 'dois' (casou, e caiu) e por 'tres' (caiu de novo).

Uma entrada, três trechos executados — é o que o fallthrough significa.

A terceira função é o uso legítimo: nivel(1) e nivel(2) caem no mesmo

return, e a linha sai case compartilhado: iniciante | iniciante | sem nivel.

Os dois case empilhados, sem comando entre eles, é o fallthrough proposital: o

case 1 não faz nada e deixa o case 2 responder.

Os três operadores de atalho: && || e ??

O ?? é o coalescente, nome técnico de quem escolhe o valor quando falta um.

Os três não comparam nada; devolvem um dos dois lados. Cada um resolve um caso

diferente, e confundir || com ?? é o erro mais comum dos três:

OperadorDevolve o primeiro se...Usado para
`\\`for truthy`valor \\padrao`
&&for falsyusuario && usuario.nome
??for null ou undefinedconfig ?? padrao

A diferença entre || e ?? aparece com o zero:

console.log(0 || 'padrão');      // 'padrão'  <- 0 foi trocado
console.log(0 ?? 'padrão');      // 0        <- 0 foi preservado

|| troca o zero e a string vazia, porque são falsy. ?? só troca null e

undefined, que são os dois casos em que o valor realmente "não existe". Em

configuração e em valor vindo de API, ?? é o certo.

O && é o atalho de teste: se o valor da esquerda for falsy, o resultado é o

próprio valor da esquerda, e o ponto final evita acessar o que não existe:

console.log(usuario && usuario.nome);

O exemplo compara os três operadores com os valores que os diferenciam, e a

tabela acima aparece em três linhas. A primeira é o || com zero e com texto:

|| com zero: padrao | || com texto: Ana — o 0 foi trocado pelo padrão e o

'Ana' passou intacto. A segunda é o ?? com os três casos:

?? com zero: 0 | ?? com null: padrao | ?? com vazio: — o 0 foi preservado, o

null foi trocado, e a string vazia passou intacta, que é a diferença do ??

para o || em duas palavras.

O && aparece nas duas linhas seguintes, e a segunda é a que salva o app de um

erro: && evita o erro quando nao ha usuario: null. O lado esquerdo é null, e

o lado direito — null.nome, que seria um TypeError — nunca foi avaliado. É

isso que o && faz: ele devolve o valor da esquerda quando ela é falsy, e o

JavaScript não chega a olhar o resto.

A cadeia completa sai em cadeia de &&: 3: usuario é truthy, usuario.nome

é truthy, e usuario.nome.length vale 3. Três truthy encadeados, resultado

numérico. A última linha do exemplo faz o oposto do &&, que é somar || até

sair o primeiro valor truthy: primeiro valor truthy: final — '', 0 e

null foram descartados, e 'final' ganhou.

Exemplo

// Operador ternario, switch e os operadores de atalho.
const total = 3;
const status = 'pendente';
const usuario = { nome: 'Ana', notificacoes: 0 };

/* ternario: uma condicao escrita como expressao */
console.log('ternario:', total > 0 ? 'tem itens' : 'vazio');
console.log('plural dentro do texto:', `${total} tarefa${total === 1 ? '' : 's'}`);
console.log('ternario de true/false:', 1 > 0 ? 'sim' : 'nao');

/* objeto de traducao: melhor que ternario aninhado */
const precos = { basico: 10, pro: 20 };
const plano = 'pro';
console.log('preco do plano:', precos[plano]);

/* switch: o caso com nome, e o que acontece sem break */
function descreverStatus(atual) {
  let saida = '';
  switch (atual) {
    case 'pendente':
      saida += 'ainda falta';
      break;
    case 'concluida':
      saida += 'pronto';
      break;
    default:
      saida += 'desconhecido';
  }
  return saida;
}
console.log('switch:', descreverStatus('pendente'), '|', descreverStatus('concluida'), '|', descreverStatus('outro'));

// sem break, a execucao cai no case seguinte: o fallthrough
function cairNoSeguinte(n) {
  let r = '';
  switch (n) {
    case 1:
      r += 'um';
    case 2:
      r += 'dois';
    case 3:
      r += 'tres';
  }
  return r;
}
console.log('fallthrough:', cairNoSeguinte(2));

// fallthrough proposital: dois case compartilham o mesmo comando
function nivel(n) {
  switch (n) {
    case 1:
    case 2:
      return 'iniciante';
    case 3:
      return 'avancado';
    default:
      return 'sem nivel';
  }
}
console.log('case compartilhado:', nivel(1), '|', nivel(2), '|', nivel(9));

/* os tres operadores de atalho */
console.log('|| com zero:', 0 || 'padrao', '| || com texto:', 'Ana' || 'padrao');
console.log('?? com zero:', 0 ?? 'padrao', '| ?? com null:', null ?? 'padrao', '| ?? com vazio:', '' ?? 'padrao');
console.log('&& curto:', usuario && usuario.nome);
console.log('&& evita o erro quando nao ha usuario:', null && null.nome);

/* o encadeamento util no app */
console.log('cadeia de &&:', usuario && usuario.nome && usuario.nome.length);
console.log('primeiro valor truthy:', '' || 0 || null || 'final');

Saída real

ternario: tem itens
plural dentro do texto: 3 tarefas
ternario de true/false: sim
preco do plano: 20
switch: ainda falta | pronto | desconhecido
fallthrough: doistres
case compartilhado: iniciante | iniciante | sem nivel
|| com zero: padrao | || com texto: Ana
?? com zero: 0 | ?? com null: padrao | ?? com vazio: 
&& curto: Ana
&& evita o erro quando nao ha usuario: null
cadeia de &&: 3
primeiro valor truthy: final