Dia 5 — Condicionais, truthy e falsy

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

Condicionais, truthy e falsy

Aula 1

if, else if, else e switch

Decidir o caminho: if, switch e o operador ternário

if escolhe o bloco que roda: uma condição vira true ou false e o programa segue por um caminho só. A condição vai entre parênteses, o corpo entre chaves. Sem as chaves, só a primeira linha depois do if é condicional — o resto do bloco roda sempre, e o erro aparece longe do if.

const idade = 20;

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

Condições combinadas

&& exige os dois lados verdadeiros, || aceita um só, ! nega. São operadores de boolean e de valor, não comparadores: if (idade) também funciona, porque idade será convertida para true ou false (dia 5, aula 2).

if (idade >= 18 && idade <= 65) { }        // os dois lados
if (turno === 'noite' || turno === 'madrugada') { }  // um basta
if (!bloqueado) { }                         // nega

&& e || devolvem um dos operandos, não true/false: nome || 'sem nome' entrega o nome quando ele existe e o texto padrão quando não. Quando um lado e condição e o outro valor, && lê melhor: usuario && usuario.nome.

A expressao condicional numa linha é o operador ?: — o mesmo que if/else inteiro em forma de valor:

const situacao = idade >= 18 ? 'maior' : 'menor';

Regra de escolha: quando os dois lados são valores, ternário; quando os dois lados são blocos de código, if.

else if e o return antecipado

else if é um if com else que só testa a próxima condição; a primeira que casar vence e as outras nem são avaliadas. Todo if com else if devia ter else no fim, senão o caso que não casa nenhum dos testes passa sem fazer nada e ninguém descobre depois.

O if aninhado é a outra forma de decidir: um if dentro do corpo de outro, quando a segunda decisão só importa para quem já entrou no primeiro. É mais rápido de ler que uma pirâmide de else if, e vira ilegível assim que passar de dois níveis.

function situacao(nota) {
  if (nota < 0 || nota > 10) {
    return 'nota invalida';
  } else if (nota >= 7) {
    return 'aprovado';
  } else if (nota >= 5) {
    return 'recuperacao';
  } else {
    return 'reprovado';
  }
}

O return sai da função imediatamente: é o "corta aqui" do JavaScript, e a forma mais direta de sair da função antes de chegar ao fim. O mesmo raciocínio vale sem else if — quem escreve a condição mais específica primeiro evita o bloco de return repetido.

switch

Palavra-chaveOnde entraO que faz
switchswitch (expressao) { }abre a estrutura e avalia a expressão uma vez
casecase valor:compara o valor com a expressão usando ===
breakbreak;sai do switch e cai na linha depois do }
defaultdefault:roda quando nenhum case casou

switch é para valor exato: código de estado, tipo de pedido, mês do ano. Compara com === estrito, então switch (tipo) com case '1' não casa com o número 1. A posição do default não muda nada: ele é testado depois de todos os case.

Sem break, o case executa e cai no seguinte (fall-through). É o que permite casos empilhados de propósito:

switch (sigla) {
  case 'S':
  case 'SS':
    console.log('segunda');
    break;
  case 'Q':
    console.log('quarta');
    break;
  default:
    console.log('sigla invalida');
}

break dentro de um switch que está dentro de um laço sai do switch, não do laço. Para sair do laço, o break precisa estar no corpo do laço — ou o switch inteiro tem que devolver por return. E o break do case é opcional quando cada case termina em return: sem ele, o próximo case roda com o mesmo argumento.

Exemplo

'use strict';
// Exemplo: as quatro portas de decisao do JavaScript.
// if escolhe por intervalo; switch escolhe por valor exato.

const nota = 6.5;

// if / else if / else: a primeira condicao verdadeira leva o controle.
if (nota >= 7) {
  console.log('aprovado');
} else if (nota >= 5) {
  console.log('recuperacao');
} else {
  console.log('reprovado');
}

// && exige os dois lados, || aceita um so, ! nega.
const idade = 17;
const turno = 'madrugada';
const urgente = false;
if (idade >= 18 && turno === 'noite') {
  console.log('processado na hora');
}
if (turno === 'noite' || turno === 'madrugada') {
  console.log('o || disparou com um lado so:', turno);
}
if (!urgente) {
  console.log('o ! negou o false, entao isto imprime');
}

// return antecipado: sai da funcao antes do resto do codigo.
function situacao(valor) {
  if (valor < 0 || valor > 10) {
    return 'nota invalida';
  }
  if (valor >= 7) {
    return 'aprovado';
  }
  return 'reprovado';
}
console.log('situacao(8):', situacao(8), '| situacao(12):', situacao(12));

// switch compara com === estrito: 1 e o numero, nao a letra.
function nomeDoDia(numero) {
  switch (numero) {
    case 1:
      return 'segunda';
    case 2:
      return 'terca';
    case 6:
      return 'sabado';
    default:
      return 'dia invalido';
  }
}
console.log('switch:', nomeDoDia(1), nomeDoDia(6), nomeDoDia(9));

// O fall-through de proposito: casos empilhados compartilham o mesmo corpo.
function diaUtil(sigla) {
  switch (sigla) {
    case 'S':
    case 'SS':
      return 'util';
    case 'Q':
      return 'teste';
    default:
      return 'descanso';
  }
}
console.log('diaUtil S, SS, Q, D:', diaUtil('S'), diaUtil('SS'), diaUtil('Q'), diaUtil('D'));

// O fall-through sem break: o case 2 continua executando o case 3.
let nivel = 0;
switch (2) {
  case 1:
    nivel = nivel + 10;
  case 2:
    nivel = nivel + 100;
  case 3:
    nivel = nivel + 1000;
    break;
  default:
    nivel = -1;
}
console.log('switch(2) sem break no case 2 soma', nivel);

// Sombreamento: o const de dentro esconde o de fora e nao altera o de fora.
const total = 'global';
if (total === 'global') {
  const total = 'interno';
  console.log('dentro do if:', total);
}
console.log('fora do if:', total);

Saída real

recuperacao
o || disparou com um lado so: madrugada
o ! negou o false, entao isto imprime
situacao(8): aprovado | situacao(12): nota invalida
switch: segunda sabado dia invalido
diaUtil S, SS, Q, D: util util teste descanso
switch(2) sem break no case 2 soma 1100
dentro do if: interno
fora do if: global
Aula 2

Truthy, falsy e o operador ternario

Truthy e falsy: os valores que viram true ou false

Toda condição é convertida em boolean antes de ser testada. O que essa conversão devolve é o que se chama de truthy (vira true) e falsy (vira false). A lista de valores falsos é curta e fechada: são oito, e qualquer outro valor é verdadeiro. Nenhum objeto é falso — nem [], nem {}.

O nome em inglês é truthy e falsy; em português o termo técnico é conversão para booleano. É a mesma regra que decide um if, um while e um &&.

Os valores falsos

São oito, e document.all — o único objeto falso, que só existe no navegador — é o nono caso, à parte. Em cima de tudo isso, o typeof de cada um:

ValortypeofObservação
falsebooleano literal
0numbero número zero
-0numbero mesmo zero, com sinal contrário
0nbigintzero de BigInt
""stringstring vazia; " " com um espaço já é verdade
nullobjectausência declarada de valor
undefinedundefinedvariável sem valor, ou que não existe
NaNnumberresultado numérico inválido

São verdadeiros, contra a intuição: [], {}, "0", "false", Infinity, -1 e qualquer função. new Boolean(false) é verdade, porque o objeto existe — o que está dentro dele não conta. Boolean e !! só olham o valor, nunca o conteúdo.

Converter sem perguntar no console

FunçãoAssinaturaExemplo
BooleanBoolean(valor): booleanBoolean("0") devolve true
!!!!valoratalho de Boolean; use dentro de condição
StringString(valor): stringString(0n) devolve "0", sem o n
NumberNumber(texto): numberNumber("") devolve 0
parseIntparseInt(texto, base): numberparseInt("10px") devolve 10
typeoftypeof valor: stringtypeof naoDeclarada devolve "undefined" sem erro

!! aplica Boolean duas vezes: a primeira converte, a segunda nega. É o jeito de escrever uma condição booleana sem if, e o que a API do navegador espera quando pede "só quando for verdadeiro".

O ternário

condicao ? valorSeVerdadeira : valorSeFalsa é uma expressão: devolve um valor e cabe onde um valor cabe — em const, dentro de ${}, no argumento de uma função.

const situacao = media >= 7 ? 'aprovado' : 'reprovado';
const total = 1;
const lista = `${total} item${total === 1 ? '' : 'ns'}`;

Com o ternário, a regra é: quando os dois lados são valores, ternário; quando os dois lados são blocos de código, if. if (x) { const a = 1; } else { const a = 2; } não é ternário — é if escrito de um jeito que ninguém consegue ler.

switch, ternário ou if: qual usar

O switch é a terceira forma de decidir, e o critério é o tipo de dado. Ele compara a expressão com === contra cada case valor e, sem break no fim, o caso executado cai no seguinte — o fall-through, que é erro na maioria das vezes e proposital em casos empilhados.

Palavra-chaveOnde entraO que faz
switchswitch (expressao) { }avalia a expressão uma vez e abre a estrutura
casecase valor:compara com === e, se casar, executa daqui para baixo
breakbreak;sai do switch e pula para a linha depois do }
defaultdefault:roda quando nenhum case casou

A interação com truthy é o que surpreende: como a comparação é ===, o switch não converte tipo. switch (0) não casa com case '0', e NaN não casa com nenhum case, porque nenhuma igualdade com NaN é verdadeira. Um switch sem break e sem return no fim de cada caso é a origem clássica de resultado errado — e é o switch sem break que o professor aponta primeiro quando o resultado sai errado sem erro nenhum.

Quando a decisão cabe numa linha e os dois lados são valores, a expressão condicional (?:) é a condicional compacta: mesmo resultado do if/else, uma linha só, e devolve valor. Quando o que muda é o tipo, vai de switch; quando os dois lados são blocos de código, vai de if.

switch (x = 5) tem um sinal de igual só: o JavaScript lê como atribuição, o x passa a valer 5, e o 5 é truthy — então o default nunca roda e nenhum case casa. O teste de igualdade é ===. E typeof null devolve "object": é defeito antigo da linguagem, null nunca foi objeto, e o typeof é a única coisa que ainda mente sobre isso.

Exemplo

'use strict';
// Exemplo: quantos valores sao falsos na pratica, e o que o ternario le.
// Tudo que esta no array vira condicao de if em algum lugar do codigo.

const valores = [false, 0, -0, 0n, '', ' ', null, undefined, NaN,
  1, -1, '0', 'false', [], {}, Infinity];

// Rotulo legivel: String(0n) e "0", igual ao numero 0, entao o tipo entra.
function rotulo(valor) {
  if (typeof valor === 'bigint') {
    return valor + 'n (bigint)';
  }
  if (typeof valor === 'string') {
    return JSON.stringify(valor) + ' (string)';
  }
  if (Array.isArray(valor)) {
    return '[] (array)';
  }
  if (valor === null) {
    return 'null (object!)';
  }
  if (typeof valor === 'number' && Number.isNaN(valor)) {
    return 'NaN (number)';
  }
  if (typeof valor === 'object') {
    return '{} (object)';
  }
  return String(valor) + ' (' + typeof valor + ')';
}

console.log('valor'.padEnd(24), 'typeof'.padEnd(9), 'Boolean', '!!');
for (const valor of valores) {
  console.log(rotulo(valor).padEnd(24), String(typeof valor).padEnd(9),
    String(Boolean(valor)).padEnd(7), String(!!valor));
}

// !! e o atalho de Boolean: converte e nega, sem escrever o if.
const nome = '';
console.log('!!nome:', !!nome, '| nome || padrao:', nome || 'sem nome');
console.log('!!lista vazia:', !![], '| !!objeto vazio:', !!{});

// O ternario devolve valor: cabe em const, em interpolacao, em argumento.
const total = 1;
console.log(`${total} item${total === 1 ? '' : 'ns'}`);

const situacao = (itens) => (itens > 0 ? 'com dados' : 'vazia');
console.log('situacao(0):', situacao(0), '| situacao(7):', situacao(7));

// typeof em variavel que nao existe devolve "undefined" e nao levanta erro.
console.log('typeof naoDeclarada:', typeof naoDeclarada);

// O erro classico: um sinal de igual so. O JavaScript le como atribuicao,
// o x passa a valer 5 e a condicao e sempre verdadeira.
let x = 0;
if (x = 5) {
  console.log('entrou sempre, e x agora vale', x);
}

Saída real

valor                    typeof    Boolean !!
false (boolean)          boolean   false   false
0 (number)               number    false   false
0 (number)               number    false   false
0n (bigint)              bigint    false   false
"" (string)              string    false   false
" " (string)             string    true    true
null (object!)           object    false   false
undefined (undefined)    undefined false   false
NaN (number)             number    false   false
1 (number)               number    true    true
-1 (number)              number    true    true
"0" (string)             string    true    true
"false" (string)         string    true    true
[] (array)               object    true    true
{} (object)              object    true    true
Infinity (number)        number    true    true
!!nome: false | nome || padrao: sem nome
!!lista vazia: true | !!objeto vazio: true
1 item
situacao(0): vazia | situacao(7): com dados
typeof naoDeclarada: undefined
entrou sempre, e x agora vale 5