Control Flow & Iterações

Fluxo de Controle (Control Flow)

No universo do Javascript e também da computação, e isso inclui outras linguagens de programação, ok?

Nos temos o famoso Control Flow, que traduzido para o bom português significa Fluxo de Controle. Que nada mais é do que a ordem na qual o computador executa as instruções que você escreve para ele.

Sendo assim, o código que informamos é executado deste a primeira linha, passando pela segunda, indo para a terceira até executar a última linha. 

Veja só um exemplo de fluxo de controle por meio do comando console.log():

console.log('Eu serei executado PRIMEIRO!');

console.log('Olha, vejam só... eu sou o segundo da fila =)');

console.log('Terceiroooo!');

console.log('Pois bem... parece que eu fiquei por último rs');

Hoje existem estruturas que são capazes de "quebrar" esse fluxo de controle, de modo que o computador volte a executar aquela linha de código mais tarde, seja porque ela ainda não foi chamada, ou porque se tratam de estruturas condicionais ou iterações (loops).

Agora que já temos uma noção do que significa o Control Flow, podemos seguir mais a diante com nosso conteúdo.

Declaração em Bloco

Em conteúdos passados, nós aprendemos um pouco mais sobre a estrutura de um código em Javascript.

Onde lá nós vimos que um código em javascript, também pode ser escrito dentro das chaves {}, o que significa que estamos usando a famosa estrutura de blocos, ou mundialmente conhecida como declaração composta (compound).

Um bloco é usado para agrupar nenhuma, uma ou mais declarações em conjunto.

{
//Bloco vazio
}

{
Lista_de_Declarações (uma apenas)
}

{
Lista_de_Declarações 01
Lista de Declarações 02
}

Existem estruturas básicas em Javascript, que utilizam de forma padrão a declaração em blocos, e o primeiro que iremos conhecer será o famoso IF/ELSE.

Estrutura Condicional (IF..ELSE)

Como o próprio nome já nos diz, a estrutura condicional é uma estrutura do JS, que verifica se uma determinada condição atende a algum padrão especificado.

Se está condição for verdadeiro, um bloco de código será executado, caso seja falso, o computador seguirá por um outro caminho.

Com isso temos a a estrutura condicional If que permite que o JS execute um trecho de código, somente se uma determinada condição for verdadeira.

A sintaxe do If é a seguinte:

if(condicao){
//Lista de comandos a serem executados caso a 'condicao' for true
}

Repare que na sintaxe acima estamos fazendo o uso da declaração em bloco por meio das chaves {}.

É importante ressaltar que de forma padrão o comando if só executa aquele bloco de código caso a condição for verdadeira:

if(true){//O bloco do IF é executado pois retorna true
console.log('Eu serei executado =)');
}

if(false){//O bloco do IF não é executado pois ele retorna false
console.log('Eu nunca serei executado =(');
}

Talvez você ainda não veja uma grande utilidade do comando IF, mas entenda que ele pode e deve ser usado em conjunto com os operadores que aprendemos no conteúdo passado:

if(5 > 3){//O bloco do IF é executado, pois a operação retorna verdadeiro
console.log('Realmente... 5 é maior que 3!');
}

if('Micilini' == 13){//O bloco do IF não é executado, pois o retorno é falso
console.log('Não serei executado mesmo...');
}

let soma = 1 + 2;
if(soma == 3){//O bloco é executado pois o resultado é 3
console.log('Só para você saber que podemos passar e usar variáveis dentro do IF');
}

if(!false){//Lembra do operador de negação? Aqui ele transforma o false em true, e como consequência ele executa o bloco do IF
console.log('Eu serei executado!!!');
}

if(!(soma == 2)){//Apesar da soma ter dado 3 e inicialmente retornar false (pois 3 é diferente de 2). Por meio da negação, false se torna true, e o bloco é executado.
console.log('Fui executado...');
}

Podemos fazer o uso do IF de forma aninhada com outros IFs, vejamos:

let nome = "micilini";
let url = "https";

if(nome == "micilini"){
if(url == "https"){
console.log('O portal da Micilini é seguro, pois usa HTTPS');
}
if(url == "http"){
console.log('O portal da Micilini NÃO é seguro, pois usa HTTP');
}
}

Legal, não acha? E podemos continuar aninhando IFs dentro de IFs até o infinito e além, como diz o buzz lightyear 😂

Em conjunto com o If, podemos utilizar o Else. Nesse caso se o IF verifica se uma determinada condição é verdadeira para executar um bloco, o Else (se não) só pode executar outro bloco caso a condição não passar pelo IF.

A sintaxe do Else costuma ficar colada ou bem próxima o fechamento da chave do IF:

if(condicao){
//Executa todos os comandos dentro desse bloco caso a condição for verdadeira
}else{
//Executa todos os comandos dentro desse bloco caso a condição for falsa
}

Vejamos agora, o Else entrando em ação:

if(true){//Advinha qual bloco será executado...
console.log('Condição Verdadeira');
}else{
console.log('Condição Falsa');
}

if(false){//Advinha qual bloco será executado...
console.log('Condição Verdadeira');
}else{
console.log('Condição Falsa');
}

É importante ressaltar que podemos aninhar diversos if/else dentro de outros:

let nome = "micilini";
let url = "https";

if(nome == "micilini"){
if(url == "https"){
console.log('A URL é HTTPS'); 
}else{
console.log('Eu não sei o valor da url, mas ela é tudo... menos HTTPS');
}
}else{
if(nome == "micilini.com"){
console.log('Então o usuário digitou o domínio...');
}else{
console.log('É... pelo menos eu tentei verificar se ainda era "micilini.com" rs');
}
}

E podemos continuar aninhando IFs dentro de IFs até o infinito e além, como diz o buzz lightyear 😂  (novamente)!

Então quer dizer que o bloco do IF só é executado caso a condição for true, e o bloco do else caso a condição for false? Sim!

Sem as Chaves {}

É possível escrever uma estrutura IF..ELSE sem a necessidade de utilizar as chaves? Sim é possível, mas você precisa entender que:

  • Com as chaves podemos executar mais de duas linhas de códigos,
  • Sem as chaves estamos limitados a executar somente uma linha de código.
/* IF/ELSE sem as chaves */

if(true)
console.log('É verdadeiro');
else
console.log('É falso');

/* IF/ELSE sem as chaves com mais de uma linha de código (NÃO VAI FUNCIONAR) */

if(true)
console.log('É verdadeiro');
let soma = 1 + 1;//Essa linha vai dar erro
console.log(soma);//E essa linha também
else
console.log('É falso');
console.log('O código já deu problema mesmo...');//Essa linha não costuma dar problema, veremos em mais detalhes a seguir...

Existem situações em que dá a impressão de que o IF sem as chaves, está executando mais de uma linha de código, como é o caso do exemplo abaixo:

if(true)
console.log('Bloco do IF');
console.log('Restante da Execução do código');

O que acontece é que o IF sozinho sem as chaves (e também sem a presença do ELSE), ele executa a próxima linha como se ela não estivesse dentro das chaves. De modo que tudo o que vem depois, é considerado algo que está fora do bloco.

Ou seja, é como se tivéssemos escrito nosso código dessa forma:

if(true){
console.log('Bloco do IF');
}

console.log('Restante da Execução do código');//Independente se o bloco do if foi executado, o JS ainda executa os próximos código.

Já quando o ELSE se faz presente, não podemos declarar duas linhas dentro do IF, mas podemos fazer isso após a primeira linha do ELSE, pois o JS não considera o que vier depois como um código dentro do bloco:

if(true)
console.log('Bloco do IF');
else
console.log('Bloco do ELSE');
console.log('Restante da Execução do código, que não se encontra dentro do bloco do ELSE!');

Ou seja, nesse caso é como se estivéssemos escrevendo o código dessa forma:

if(true){
console.log('Bloco do IF');
}else{
console.log('Bloco do ELSE');
}
console.log('Restante da Execução do código, que não se encontra dentro do bloco do ELSE!');

IFs seguidos de IFs

No Javascript também podemos declarar IFs em conjunto, vejamos a sintaxe:

if(condicao){

} if(condicao_02){

}else{

}

No caso podemos ter quantos IFs quisermos. Vejamos um exemplo prático:

let categoriaDeMotorista = "A";

if(categoriaDeMotorista == "A"){
console.log('Motos e Triciclos');
} if(categoriaDeMotorista == "B"){
console.log('Carros de Passeio');
} if(categoriaDeMotorista == "C"){
console.log('Veículos de Carga acima de 3,5 tonelada...');
}else{
console.log('Pesquisa pelas categorias D e E');
}

É importante ressaltar que podemos ter inúmeros IFs, mas somente um único ELSE.

Iterações

Quando se trata de iterações (também conhecidas como laços ou loops), estamos nos referindo a ações que são, e podem ser executadas repetidas vezes de forma automática pelo JS.

Veremos cada uma das iterações a seguir!

Switch

No Javascript nós temos uma condicional chamada switch, que por sua vez, avalia uma condição, e executa o bloco de código de acordo com o seu resultado.

O switch pode ser considerado uma estrutura de laços.

A sintaxe do switch é a seguinte:

switch (expressão) {
case valor1:
//Instruções executadas quando o resultado da expressão for igual á valor1
[break;]
case valor2:
//Instruções executadas quando o resultado da expressão for igual á valor2
[break;]
...
case valueN:
//Instruções executadas quando o resultado da expressão for igual á valorN
[break;]
default:
//Instruções executadas quando o valor da expressão é diferente de todos os cases
[break;]
}

Vejamos agora um exemplo prático:

let produto = "tablet";

switch (produto) {
case "notebook":
console.log('Notebook por apenas R$ 2.000');
case "desktop":
console.log('Desktop por apenas R$ 5.000');
case "tablet":
console.log('Tablet por apenas R$ 1.200');
default:
console.log('Só estamos vendendo Notebooks, Desktops e Tablets no momento...');
}

No código acima ele avalia o valor existente dentro da variável chamada produto.

E dá algumas possibilidades que podem ser encontradas, tais possibilidades que já foram previamente declaradas dentro do comando case, que significa "caso"

Ou seja:

  • "caso o valor existente dentro da variável produto for igual a notebook, ele mostra o preço do notebook".  
  • "caso o valor existente dentro da variável produto for igual a desktop, ele mostra o preço do desktop".  
  • "caso o valor existente dentro da variável produto for igual a tablet, ele mostra o preço do tablet".  

O comando default, é usado sempre quando a opção não for encontrada.

Como é o caso de colocarmos o texto 'smartphone' dentro da variável produto, fazendo com que o switch execute o default.

Se você testar esse código acima, vai perceber que diversas mensagens podem ser mostradas em vez de uma.

Por exemplo, se o valor da variável produto fosse 'notebook', o switch não só iria mostrar o preço do notebook como também do desktop, do tablet e do valor default.

Break

O comando break encerra o loop atual de forma a transferir a execução do código para fora do bloco atual.

Este comando é muito utilizado em conjunto com o switch, pois ele consegue evitar que outras mensagens sejam executadas de forma automática.

let produto = "notebook";

switch (produto) {
case "notebook":
console.log('Notebook por apenas R$ 2.000');
break.
case "desktop":
console.log('Desktop por apenas R$ 5.000');
break;
case "tablet":
console.log('Tablet por apenas R$ 1.200');
break;
default:
console.log('Só estamos vendendo Notebooks, Desktops e Tablets no momento...');
}

console.log('Saímos do switch com o preço de um produto apenas...');

Quando utilizamos o break ao final de cada comando executado pelo case, nós estamos dizendo ao Javascript o seguinte: "Assim que encontrar o valor referente no switch, execute o comando, saia imediatamente do switch e execute tudo o que vier depois das chaves".

Lembrando que o default não precisa do break, pois ele já esta localizado na última etapa do comando switch, logo, você pode ficar tranquilo pois ele não irá executar mais nenhum código.

Nesse momento você pode estar se questionando que o switch se parece muito com a estrutura de Ifs em conjunto, e é verdade:

let produto = "notebook";

if(produto == "notebook"){
console.log('Notebook por apenas R$ 2.000');
}if(produto == "notebook"){
console.log('Desktop por apenas R$ 5.000');
}if(produto == "notebook"){
console.log('Tablet por apenas R$ 1.200');
}else{
console.log('Só estamos vendendo Notebooks, Desktops e Tablets no momento...');
}

A diferença é que no IF, não precisamos do break 😉

While

Com o comando while (enquanto), estamos fazendo com que o JS execute um bloco de código infinitamente (loop) até que uma determinada condição deixe de ser verdadeira.

A sua sintaxe é:

while (condição) {
//Executa essa rotina até que a condição deixe de ser verdadeira
}

Exemplo prático da utilização do while com loop infinito:

while(5 > 3){
console.log('5 é maior que 3');//Essa mensagem será executada infinitamente pois 5 sempre será maior que 3
}

Exemplo prático da utilização do while sem loop infinito:

var numero = 0;

while (numero < 3) {//Enquanto 0 for menor que 3 (sentença que retorna TRUE), ele vai executar o bloco abaixo
numero++;//Toda vez que ele executa esse loop o valor de 'numero' receberá mais 1
}

console.log('Parabéns você saiu do While, o valor de "numero" é ' + numero);

No caso do comando acima, toda vez que o loop era executado ele adicionava + 1 a variável número, de modo que o javascript fazia as seguintes análises:

  • Loop 1) 0 é menor que 3? Sim... execute o bloco de código (numero = 1)
  • Loop 2) 1 é menor que 3? Sim... execute o bloco de código (numero = 2)
  • Loop 3) 2 é menor que 3? Sim... execute o bloco de código (numero = 3)
  • Tentativa 4) 3 é menor que 3? Não... então não execute o bloco de código e saia do loop.

Continue

Dentro de um bloco de código do tipo iterativo, nós podemos ter inúmeros códigos, como por exemplo:

//código 00 (fora do bloco)

{
//código 01 (dentro do bloco)
//código 02 (dentro do bloco)
//código 03 (dentro do bloco)
}

//código 04 (fora do bloco)
//código 05 (fora do bloco)

Mas e se houvesse uma maneira de fazer com que os códigos 02 e 03 NÃO sejam executados após o código 01

Ou seja, e se houvesse uma maneira de pular a execução de tais códigos de modo a fazer com que o JS saia daquele bloco de código? Isso é possível?

Sim, por meio do comando continue.

É importante ressaltar que este comando só funciona se estiver dentro de uma iteração (dentro de um for, while ou um switch).

Mas será que ele funciona se estiver dentro de um IF/ELSE por exemplo? Sim, desde que esse IF/ELSE exista de forma aninhada dentro de uma iteração.

Vejamos como este comando se comporta dentro do while:

let numero = 0;

while(numero < 3){
numero++;
if(numero == 2){
continue;//Não gosto do número 2, portanto não quero receber a mensagem que estou nele. Pulo os códigos abaixo.
}
console.log('Atual: ' + numero);
}

console.log('Numero: ' + numero);

De acordo com a lógica acima, parece que quem escreveu o código está pulando a mensagem 'Atual: 2', talvez o desenvolvedor não goste desse número😅

While com Break

Quando utilizamos o break dentro de um while, fazemos com que o javascript saia daquele loop independentemente se a condição continua sendo verdadeira ou não.

var numero = 0;

while(numero < 10){
if(numero == 3){
console.log('Aí... cansei desse loop vou sair!');
break;
}
numero++;
}

console.log('Voce saiu do Loop e só contou até: ' + numero);//valor de 'numero' será 3

Do...While

Este comando funciona de forma parecida com o while, a diferença é que ele executa mais um loop antes de sair daquele loop

Como o próprio nome já nos diz, DO significa 'faça', enquanto 'while' significa 'enquanto', portanto, podemos dizer que primeiro ele executa o bloco de código para depois verificar se pode continuar executando ou não.

O que funciona de forma diferente do while sozinho, que primeiro verifica se pode executar o bloco para em seguida entrar nele.

A sintaxe do do..while é a seguinte:

do{

}while(condicao);

Vejamos um exemplo dele:

var numero = 0;

do{
numero++;
}while (numero < 3);

console.log('Parabéns você saiu do do...while, o valor de "numero" é ' + numero);//3

Espere... por que o resultado da variável numero é igual a 3? Isso aconteceu porque primeiro ele executa o do, e depois verifica se vai continuar no loop ou não.

Diferente do while abaixo, em que o resultado da variável número é 2, pois primeiro ele verifica se pode executar o bloco, e caso verdadeiro ele o executa:

var numero = 0;

while (numero < 3) {
numero++;
}

console.log('Parabéns você saiu do While, o valor de "numero" é ' + numero);//2

Do...While com Break

Assim como o while, podemos fazer o uso do break para sair daquele loop:

var numero = 0;

do{
if(numero == 3){
console.log('Aí... cansei desse loop vou sair!');
break;
}
numero++;
}while(numero < 10);

console.log('Voce saiu do Loop e só contou até: ' + numero);//valor de 'numero' será 3

No código acima o resultado da variável número resultou em 3 e não 4, pois impedimos a execução do comando numero++;, mas perceba que mesmo assim o bloco do do foi executado.

For

A instrução For é uma forma automatizada de fazer iterações no javascript, pois com ela conseguimos declarar o valor de uma variável, a condição e ainda se vamos acrescentar + 1 ou diminuir -1 da variável que criamos.

Isso tudo dentro de uma mesma expressão.

A sintaxe do For é a seguinte:

for ([inicialização]; [condição]; [expressão final]){
//Lista de comandos
}

Vejamos um exemplo simples da utilização do for:

for (var i = 0;i < 0;i++) {
console.log(i);
}

//O comando acima fará a contagem de 0 até 8.

No comando acima, declaramos a variável chamada i que começa com o valor de 0, dizemos que esse loop vai continuar sendo executado até que i seja menor que 9, onde a cada iteração o valor de i será acrescido de 1.

Expressões (For) Opcionais

É importante ressaltar que todas as expressões que podemos passar pelo for ([inicialização]; [condição]; [expressão final]), são totalmente opcionais, isso significa dizer que:

1) É possível iniciar um for sem a inicialização de uma variável:

var i = 0;
for (; i < 0;i++) {
console.log(i);
}

2) É possível iniciar um for sem uma condição:

for (var i = 0;; i++) {
console.log(i);
if (i > 3) break;
}

3) É possível iniciar um for sem uma expressão final:

for(var i = 0;i < 3;){
console.log(i);
i++;
}

4) É possível iniciar um for sem expressão nenhuma:

var i = 0;

for (;;) {
if (i > 3) break;
console.log(i);
i++;
}

Lembrando que podemos utilizar tanto os comandos break e continue dentro do For, ok?

Try...Catch

Como o nome já nos diz, try significa tentar, e catch significa pegar.

Traduzindo... o javascript tenta executar o bloco de código do try, e se alguma coisa der errado, um outro bloco será executado, que no caso seria o bloco do catch.

A sintaxe do try...catch é a seguinte:

try {
//Linha de códigos
}catch(variavelDeexcecao){
//Linha de códigos
}

Para que o bloco do catch seja executado precisamos criar uma exceção dentro do bloco try, e para isso usamos o comando throw.

Throw

A declaração throw lança uma exceção definida pelo usuário.

Ela funciona em conjunto com a expressão try...catch que vimos anteriormente.

Quando esse comando é executado, o javascript para a execução dos outros códigos existentes no bloco try e começa a executar os códigos existentes no bloco catch.

try {
throw "Minha Excecao"; // gera uma exceção no bloco
console.log('Nunca serei executado...');
}
catch (e) {
console.error(e); //A variável e armazena todas as informações do erro
}

...Finally

Em conjunto com a expressão try...catch podemos adicionar mais uma cláusula chamada finally.

Ela sempre é executada, independente se uma exceção for lançada ou capturada.

try {
throw "Minha Excecao"; // gera uma exceção no bloco
console.log('Nunca serei executado...');
}
catch (e) {
console.error(e); //A variável e armazena todas as informações do erro
}
finally{
console.log('Caiu no try ou catch? Não importa, eu continuo sendo executado no final');
}

Try...Finally

É possível também utilizar o bloco try sem catch, você sabia disso?

try {
throw "Minha Excecao"; // gera uma exceção no bloco
console.log('Nunca serei executado...');
}
finally{
console.log('Caiu no try ou catch? Não importa, eu continuo sendo executado no final');
}

No caso do comando acima, o throw ainda será lançado e a execução irá parar, mas como o bloco catch não existe, ele vai direto para o bloco finally.

O problema é que isso irá gerar um erro no Javascript! Pois ele precisa que o catch seja declarado quando temos uma exceção.

Blocos Try aninhados

Também é possível fazer o uso dos blocos try...catch...finally de forma aninhada (um dentro do outro):

try {
try {
throw "Minha Exceção";
}
catch (e) {
console.error(e);//esse comando será executado
}
finally {
console.log("Bloco Finally");
}
}
catch (e) {
console.error(e);//este comando nunca será chamado
}

É importante ressaltar que qualquer exceção lançada será capturada apenas uma vez pelo bloco catch envolvente mais próximo, a não ser que seja relançada.

Então no caso do comando acima, quando executamos o throw "Minha Exceção"; o catch mais próximo será executado.

Agora caso dentro desse bloco catch existir uma outra exceção, outro bloco catch será chamado, por exemplo:

try {
try {
throw "Minha Exceção";
}
catch (e) {
console.error(e);//esse comando será executado
throw "Minha Exceção 02";
}
finally {
console.log("Bloco Finally");
}
}
catch (e) {
console.error(e);//este comando será executado por causa do 'throw "Minha Exceção 02";'
}

Conclusão

Neste conteúdo aprendemos um pouco mais sobre os fluxos de controle e também sobre iterações no Javascript.

Recomendamos revisar este conteúdo diversas vezes para que você fique familiarizado com essas estruturas 🤓

Até o próximo conteúdo 😄