Skip to content
This page has been auto-translated and may contain errors.View in English

Condicionais

docs.scrimba.com

Um programa que sempre faz a mesma coisa não é muito útil. Você quer uma página que mostra uma mensagem para um visitante logado e outra para um desconhecido, um formulário que aceita idade de 18 mas não de 12, um jogo que informa se você ganhou ou perdeu. Tudo isso precisa de uma forma de fazer uma pergunta e agir conforme a resposta. É para isso que servem condicionais: elas permitem que seu código escolha o que executar baseado em se algo é verdadeiro.

Você já tem as peças. Os operadores de comparação e lógicos produzem respostas verdadeiras ou falsas, e este capítulo é sobre agir conforme elas.

Executando código apenas quando uma condição é verdadeira

Um if statement executa um bloco de código apenas quando uma condição é verdadeira. Você escreve a palavra if, uma condição entre parênteses, e um bloco entre chaves. Se a condição for verdadeira, o bloco executa. Se não for, JavaScript pula o bloco e continua.

js
const age = 20;

if (age >= 18) {
  console.log("Você pode entrar."); // Você pode entrar.
}

A condição age >= 18 é verdadeira ou falsa. Aqui age é 20, então é verdadeira, e a mensagem é impressa. Mude age para 12 e a condição é falsa, então o bloco é pulado e nada é impresso.

Frequentemente você quer uma alternativa para quando a condição é falsa. É para isso que else serve:

js
const age = 12;

if (age >= 18) {
  console.log("Você pode entrar.");
} else {
  console.log("Volte quando ficar mais velho."); // Volte quando ficar mais velho.
}

Exatamente um dos dois blocos executa, nunca ambos. Quando você tem mais de dois resultados, else if permite que você verifique outra condição:

js
const score = 74;

if (score >= 90) {
  console.log("Nota: A");
} else if (score >= 70) {
  console.log("Nota: B"); // Nota: B
} else {
  console.log("Nota: C");
}

JavaScript verifica cada condição de cima para baixo e para na primeira que é verdadeira. Uma pontuação de 74 não é >= 90, mas é >= 70, então imprime Nota: B e nunca olha para o else.

Um if statement executa um bloco quando sua condição é verdadeira, e um bloco else opcional executa quando não é. Encadear com else if permite que você verifique várias condições em ordem.

js
const score = 74;

if (score >= 90) {
  console.log("Nota: A");
} else if (score >= 70) {
  console.log("Nota: B"); // Nota: B
} else if (score >= 50) {
  console.log("Nota: C");
} else {
  console.log("Nota: F");
}

A ordem é importante, e é a parte que as pessoas erram. JavaScript testa cada condição de cima para baixo e executa o bloco da primeira verdadeira, depois pula o resto. É por isso que os intervalos vão de alto para baixo aqui: uma vez que score >= 70 é alcançado, 74 corresponde e a cadeia para. Se você escrevesse score >= 50 primeiro, 74 corresponderia a isso em vez disso e todos acima de 50 receberiam C.

A condição pode ser qualquer expressão que produz um valor verdadeiro ou falso, então você pode combinar verificações com os operadores lógicos de operadores:

js
const age = 20;
const hasTicket = true;

if (age >= 18 && hasTicket) {
  console.log("Aproveite o show."); // Aproveite o show.
} else {
  console.log("Entrada recusada.");
}

Um if statement avalia uma condição e executa seu bloco quando o resultado é verdadeiro, com ramos else if e else opcionais para os outros casos. A cadeia é ordenada: JavaScript avalia condições de cima para baixo e executa o primeiro bloco cuja condição é verdadeira, depois sai de toda a cadeia.

js
const score = 74;

if (score >= 90) {
  console.log("Nota: A");
} else if (score >= 70) {
  console.log("Nota: B"); // Nota: B
} else if (score >= 50) {
  console.log("Nota: C");
} else {
  console.log("Nota: F");
}

Duas propriedades dessa forma valem a pena guardar. Primeiro, os ramos são mutuamente exclusivos: exatamente um executa. É por isso que os limites aqui só precisam de um lado cada. O ramo score >= 70 não precisa de score < 90 guardando-o, porque chegar àquela linha já significa que o teste score >= 90 falhou. Adicionar o limite superior redundante é um instinto comum e torna a cadeia mais difícil de ler, não mais segura.

Segundo, a condição é coagida para booleano, então não precisa ser uma comparação literal. Qualquer expressão funciona, e JavaScript aplica suas regras truthy e falsy para decidir. Essa flexibilidade é útil e ocasionalmente uma armadilha, é por isso que o nível avançado deste capítulo volta a ela em detalhes abaixo.

js
const age = 20;
const hasTicket = true;

if (age >= 18 && hasTicket) {
  console.log("Aproveite o show."); // Aproveite o show.
} else {
  console.log("Entrada recusada.");
}
JunoExecutando código apenas quando uma condição é verdadeira Um if executa seu bloco apenas quando a condição entre parênteses é verdadeira, e else oferece uma alternativa para quando não é. Adicione else if quando há mais de dois resultados. JavaScript verifica de cima para baixo e para na primeira correspondência, então coloque suas condições em uma ordem que faça sentido.
JunoExecutando código apenas quando uma condição é verdadeira Uma cadeia if / else if / else executa o bloco da primeira condição verdadeira e pula o resto, então a ordem não é decoração, é lógica. Intervalos vão de alto para baixo exatamente por isso. A condição pode ser qualquer expressão que resolve para verdadeiro ou falso, então combine verificações com os operadores lógicos quando precisar.
JunoExecutando código apenas quando uma condição é verdadeira A cadeia é mutuamente exclusiva e avaliada de cima para baixo, então cada ramo só precisa do limite que os ramos acima não descartaram. Adicionar o limite superior redundante parece cautela mas é realmente apenas ruído. E a condição é coagida para booleano, que é um recurso até um valor inesperado passar, então mantenha as regras truthy e falsy em mente.

Escolhendo um valor com o operador ternário

Às vezes um if / else faz um pequeno trabalho: escolher entre dois valores. Para isso há uma forma mais curta chamada operador ternário. Você escreve uma condição, um ?, o valor a usar quando é verdadeiro, um :, e o valor a usar quando é falso.

js
const age = 20;
const message = age >= 18 ? "Bem-vindo" : "Muito jovem";

console.log(message); // Bem-vindo

Leia como uma pergunta: age >= 18? Se sim, message fica "Bem-vindo"; se não, fica "Muito jovem". É a mesma decisão que um if / else faria, em uma linha.

O ternário é melhor quando você está escolhendo um valor para guardar ou imprimir. Quando um ramo precisa fazer várias coisas, um if statement é mais claro, então use o ternário apenas quando cada lado é um único valor.

O operador ternário escolhe entre dois valores baseado em uma condição: condition ? valueIfTrue : valueIfFalse. Diferentemente de um if statement, é uma expressão, então produz um valor que você pode atribuir ou colocar direto em um template literal.

js
const score = 82;
const passed = score >= 60 ? "aprovado" : "reprovado";

console.log(`Resultado: ${passed}`); // Resultado: aprovado

É aqui que ele merece seu lugar. Atribuir um de dois valores a uma variável é um trabalho que o ternário faz em uma linha, enquanto a versão if espalha a mesma lógica por cinco linhas e repete a atribuição em ambos os ramos:

js
// A versão if faz a mesma coisa com mais cerimônia:
let passed;
if (score >= 60) {
  passed = "aprovado";
} else {
  passed = "reprovado";
}

Onde para de ajudar é quando os ramos fazem mais que produzir um valor. Se qualquer lado precisa executar várias instruções, ou você se encontra aninhando um ternário dentro de outro, a legibilidade que você ganhou desapareceu. Nesse ponto um if statement é a escolha mais clara.

O operador ternário é o único operador em JavaScript que toma três operandos: condition ? valueIfTrue : valueIfFalse. A distinção que o torna útil é que é uma expressão, não um statement. Avalia para um valor, então se encaixa em lugares onde um statement não pode ir: o lado direito de uma atribuição, um argumento, um template literal.

js
const score = 82;
const label = score >= 60 ? "aprovado" : "reprovado";

console.log(`Resultado: ${label}`); // Resultado: aprovado

Use-o quando o trabalho todo é selecionar entre dois valores, e prefira-o sobre um if lá porque mantém a atribuição em um lugar em vez de repeti-la em ambos os ramos. Use um ternário para escolher um valor, não para executar um ramo.

O modo de falha é aninhamento. Um ternário cujos ramos são eles próprios ternários tecnicamente funciona, mas força o leitor a analisar da direita para a esquerda e manter várias condições em sua cabeça de uma vez:

js
// Difícil de ler. Prefira uma cadeia if ou switch aqui.
const grade = score >= 90 ? "A" : score >= 70 ? "B" : score >= 50 ? "C" : "F";

Essa linha produz a resposta certa e custa esforço real do próximo leitor. Quando uma decisão tem mais de dois resultados, uma cadeia if ou um switch a expõem muito mais claramente, que é a próxima seção.

JunoEscolhendo um valor com o operador ternário O ternário é uma forma compacta de escolher entre dois valores: condition ? valueIfTrue : valueIfFalse. Brilha quando você está escolhendo algo para guardar ou imprimir. Se um ramo precisa fazer mais que devolver um único valor, use um if completo, lerá mais claramente.
JunoEscolhendo um valor com o operador ternário Um ternário é uma expressão, então devolve um valor que você pode atribuir ou colocar em um template literal, que um if statement não pode fazer. Isso o torna a escolha limpa para escolher um de dois valores, já que a versão if repete a atribuição em ambos os ramos. Uma vez que os ramos fazem trabalho real, ou você começa a aninhar ternários, volte para um if.
JunoEscolhendo um valor com o operador ternário O ternário é uma expressão, então vai onde um statement não pode: uma atribuição, um argumento, um template literal. Use-o para escolher um valor, não para executar um ramo, e ele permanece legível. Aninhe um dentro de outro e para de compensar, então uma decisão com vários resultados pertence a uma cadeia if ou um switch.

Comparando um valor contra casos fixos com switch

Quando você está verificando um valor contra uma lista de possibilidades definidas, um switch statement pode ser mais limpo que uma longa cadeia if / else if. Você o fornece o valor para verificar, depois lista os casos para compará-lo.

js
const day = "Ter";

switch (day) {
  case "Sab":
    console.log("Fim de semana");
    break;
  case "Dom":
    console.log("Fim de semana");
    break;
  default:
    console.log("Dia de semana"); // Dia de semana
}

O switch compara day com cada case por sua vez. Quando encontra uma correspondência, executa o código daquele case. break diz para parar; sem ele, JavaScript continua executando o próximo case. default é a alternativa que executa quando nenhum case corresponde, como o else final em uma cadeia.

Esquecer break é o erro clássico do switch. Deixe de fora e seu código executa o case correspondente e então cada case abaixo dele até que encontre um break ou o fim, que é quase nunca o que você quer dizer.

Um switch statement compara um valor contra um conjunto de casos fixos. Lê mais claramente que uma longa cadeia if / else if quando cada ramo está testando o mesmo valor para igualdade.

js
const status = "enviado";

switch (status) {
  case "pendente":
    console.log("Pedido recebido.");
    break;
  case "enviado":
    console.log("A caminho."); // A caminho.
    break;
  case "entregue":
    console.log("Entregue.");
    break;
  default:
    console.log("Status desconhecido.");
}

Três coisas carregam a lógica. case marca um valor para corresponder, break termina o case correspondente, e default lida com qualquer coisa não correspondida. A correspondência usa igualdade estrita (===), então case "1" não corresponderá a um número 1.

A pegadinha é fall-through. Um case sem um break não para; a execução continua nos cases seguintes até que encontre um break ou o fim do switch. Isso é geralmente um bug, mas também é ocasionalmente útil quando vários cases compartilham um resultado:

js
const day = "Sab";

switch (day) {
  case "Sab":
  case "Dom":
    console.log("Fim de semana"); // Fim de semana
    break;
  default:
    console.log("Dia de semana");
}

Aqui "Sab" corresponde e passa para o bloco compartilhado para "Dom", então ambos os dias de fim de semana executam a mesma linha. Esse é fall-through usado propositalmente, e só lê claramente porque os cases vazios se alinham diretamente acima do bloco compartilhado.

Um switch statement toma um único valor e o compara contra uma série de rótulos case, executando o bloco do primeiro que corresponde. A comparação é igualdade estrita (===), que é importante: case "1" não corresponde ao número 1, e não há coerção de tipo para salvá-lo.

js
const status = "enviado";

switch (status) {
  case "pendente":
    console.log("Pedido recebido.");
    break;
  case "enviado":
    console.log("A caminho."); // A caminho.
    break;
  case "entregue":
    console.log("Entregue.");
    break;
  default:
    console.log("Status desconhecido.");
}

O mecanismo que as pessoas subestimam é fall-through. Um switch não executa um case e para; ele salta para o rótulo correspondente e então executa direto até que encontre um break ou a chave de fechamento, ignorando limites de cases no caminho. Um break faltante executa cada case abaixo da correspondência. Essa é a fonte da maioria dos bugs de switch, e é também o único uso deliberado do comportamento, alinhando rótulos para que vários valores compartilhem um bloco:

js
const day = "Sab";

switch (day) {
  case "Sab":
  case "Dom":
    console.log("Fim de semana"); // Fim de semana
    break;
  default:
    console.log("Dia de semana");
}

default não precisa vir por último, embora colocá-lo por último seja a convenção que mantém switches legíveis. Note também que um switch só testa um valor para igualdade, então uma cadeia de verificações de intervalo como o exemplo de nota anterior não pode se tornar um switch. Esse limite é exatamente o que diz quando um switch é a ferramenta certa, que a última parte deste nível destrincha.

JunoComparando um valor contra casos fixos com switch Um switch verifica um valor contra uma lista de opções case e executa aquela que corresponde, com default como catch-all. Sempre termine cada case com break, ou JavaScript continua executando nos cases abaixo. Esse break faltante é o erro que quase todos cometem pelo menos uma vez.
JunoComparando um valor contra casos fixos com switch Use um switch quando cada ramo está testando o mesmo valor para igualdade contra casos fixos, e lembre-se de que ele corresponde com ===, então "1" não é 1. Cada case precisa um break ou passa para o próximo. Esse fall-through é um bug por padrão, mas alinhar cases vazios acima de um bloco compartilhado é a única vez que você quer.
JunoComparando um valor contra casos fixos com switch Um switch corresponde um valor com igualdade estrita e então executa para baixo até um break, ignorando limites de cases, então um break faltante executa cada case abaixo da correspondência. Alinhar rótulos acima de um bloco compartilhado é o único uso deliberado disso. Porque ele só testa igualdade em um único valor, um conjunto de verificações de intervalo permanece uma cadeia if.

Escolhendo a ferramenta certa

Você agora tem três formas de tomar uma decisão, e a escolha é principalmente sobre adequação. Use uma cadeia if / else if / else para a maioria da ramificação, especialmente quando as condições são intervalos ou combinações. Use um ternário quando está escolhendo um de dois valores para guardar ou imprimir. Use um switch quando está verificando um valor contra um punhado de opções fixas.

Nenhuma delas é mais avançada que as outras. Use aquela que expõe sua decisão mais claramente, e se não tiver certeza, um if statement é sempre uma escolha segura.

As três formas se sobrepõem, então a habilidade útil é corresponder a ferramenta à forma da decisão. Uma cadeia if lida com qualquer coisa, e é a opção certa sempre que as condições são intervalos (score >= 70) ou combinações (age >= 18 && hasTicket). Um ternário é para escolher entre dois valores em uma expressão. Um switch se encaixa quando um único valor é testado para igualdade contra vários casos fixos, como um status ou um nome de dia.

Uma regra evita muito código emaranhado: use a forma que lê mais claramente, não a mais curta. Um ternário aninhado é mais curto que uma cadeia if e pior de ler, então comprimento não é o objetivo. Clareza para a próxima pessoa, que frequentemente é você em um mês, é.

Três ferramentas, e os limites entre elas se resumem à forma da decisão. Uma cadeia if é a forma geral: ela lida com intervalos, combinações, e qualquer coisa que uma condição possa expressar, então é o padrão sempre que os ramos não são todos testes de igualdade em um valor. Um ternário se estreita para um único trabalho, escolher um de dois valores como uma expressão, e compensa apenas enquanto ambos os ramos permanecem simples. Um switch se encaixa quando um valor é comparado para igualdade contra um conjunto fixo de casos.

Há uma quarta opção que vale a pena nomear mesmo que esteja fora do escopo aqui: quando você está mapeando um valor para um resultado, um objeto de lookup frequentemente bate as três. Um switch que só atribui um valor por case, ou uma longa cadeia if de testes value === "x", é frequentemente mais claro como um objeto simples que você indexa. Você conhecerá esse padrão uma vez que objetos estejam na mesa; por enquanto, repare quando um switch é realmente uma tabela disfarçada.

Mais dois hábitos avançados completam isso. O primeiro é valores truthy e falsy, porque uma condição não precisa ser uma comparação. JavaScript coage a condição para um booleano, e os valores que saem falsy são um conjunto fixo e curto: false, 0, "" (a string vazia), null, undefined, e NaN. Tudo mais é truthy. É por isso que if (name) é um atalho comum para "name não está vazio", e também por que pode surpreendê-lo: um valor de 0 é um número real mas uma condição falsy, então if (count) pula o bloco quando count é 0. Conheça o conjunto falsy e essas verificações param de ser adivinhação.

O segundo é a cláusula guard. Quando uma decisão é realmente sobre sair cedo, um if profundamente aninhado lê pior que verificar a condição de saída primeiro e parar. Essa forma "verificar o caso ruim, parar, então continuar com o bom caminho" é a cláusula guard, e mantém a lógica principal sem indentação em vez de enterrada dentro de ramos. A parte de parar geralmente significa retornar de uma função, que é o próximo capítulo, funções, então o padrão completo aterrissa lá. A ideia para levar agora é que achatar uma decisão tratando o caso excepcional primeiro é quase sempre mais claro que aninhar o caso normal mais profundamente e mais profundamente.

JunoEscolhendo a ferramenta certa Use uma cadeia if para a maioria das decisões, um ternário quando está escolhendo um de dois valores, e um switch quando está correspondendo um valor contra opções fixas. Nenhuma delas é mais sofisticada que as outras. Escolha aquela que expõe sua decisão mais claramente, e padrão para if quando não tiver certeza.
JunoEscolhendo a ferramenta certa Corresponda a ferramenta à forma: if para intervalos e combinações, um ternário para escolher um de dois valores, um switch para igualdade contra casos fixos. Use a forma que lê mais claramente, não a mais curta, porque um ternário aninhado é curto e difícil de seguir. O próximo leitor é frequentemente você, então escreva para eles.
JunoEscolhendo a ferramenta certa A cadeia if é a ferramenta geral, o ternário é para escolher um de dois valores, e o switch é para igualdade contra um conjunto fixo, com um objeto de lookup frequentemente batendo um switch de mapeamento de valor uma vez que você tem objetos. Mantenha o conjunto falsy em sua cabeça (false, 0, "", null, undefined, NaN) para que um if (count) simples não o surpreenda quando a contagem é zero. E quando uma decisão é realmente uma saída antecipada, trate o caso ruim primeiro e achate o aninhamento; a cláusula guard completa aterrissa com funções.

Para onde condicionais vão a partir daqui

Condicionais são como um programa para de ser um script fixo e começa a responder à sua entrada. Você as usará constantemente, e elas se combinam com tudo ao seu redor: as respostas verdadeiras ou falsas vêm de operadores, e as decisões que você toma aqui começam a compensar uma vez que você pode executá-las repetidamente sobre dados com loops e empacotá-las em funções.

O próximo capítulo, loops, adiciona a outra metade do controle de fluxo: não apenas escolher se executar código, mas executá-lo repetidamente até uma condição dizer para parar.