No artigo anterior vimos como criar variáveis e atribuir valores à elas. Também foi mostrado alguns atalhos de atribuição e formas de modificar os valores das variáveis. Nesse texto vamos aumentar nossa compreensão de códigos em JavaScript e entender as declarações de controle que a linguagem possui.
A partir de agora nossos códigos começam a ficar mais extensos, contendo várias linhas. O console JavaScript dos navegadores não é adequado para essas situações. Salvar os códigos em arquivos JavaScript e executá-los no Node.js é uma boa opção. Para executar, por exemplo, um arquivo chamado example.js
no Node, você pode acessar o diretório do arquivo no terminal e digitar:
node example.js
Expressões e Declarações 🙝
Expressões são declarações de código que produzem um valor. Como visto anteriormente, nós utilizamos expressões a todo momento no JavaScript: uma atribuição é uma expressão, uma comparação é uma expressão, uma operação aritmética é uma expressão, entre outras.
Todavia, somente expressões não resolvem os problemas que precisamos lidar quando estamos codificando. Por exemplo, muitas vezes queremos que um fragmento do código seja executado dada uma condição; ou ainda, queremos que um trecho de código seja executado múltiplas vezes. Para isso nós utilizamos as declarações de controle de fluxo.
Declarações de controle de fluxo, também chamadas de statements, são palavras chaves que descrevem o comportamento do código. O JavaScript possui um conjunto compacto de declarações que podem ser combinadas para adicionar complexidade o seu código. Expressões também são declarações, mas possuem a diferença de que sempre retornam um valor.
Declaração de bloco 🙝
Uma das declarações mais básicas da linguagem é a de definição de bloco, utilizada para agrupar um conjunto de outras declarações. Todo bloco é delimitado por um par de chaves {…}
.
{
[declaração 1]
[declaração 2]
[declaração 3]
[…]
}
Importante: Diferente das linguagens C ou Java, no JavaScript, um bloco não define o escopo das variáveis declaradas com var
. O escopo em JavaScript está intimamente ligado com a declaração de funções. Vamos aprofundar o assunto de escopo de variáveis em artigos futuros, mas veja o exemplo abaixo para entender melhor:
var a = 0;
{
console.log(a); // → 0
var a = 1;
console.log(a); // → 1
}
console.log(a); // → 1
A variável a
não é oculta pela segunda declaração de uma variável com mesmo nome. Ambas as declarações são a mesma variável. Por isso, após a saída do bloco, o valor alterado dentro do bloco é mantido.
Declarações condicionais 🙝
Uma declaração condicional é uma declaração de controle de fluxo que executa ou não um trecho de código dependendo de uma condição booleana a ser avaliada.
Condicional única if … else
🙝
A declaração if
tem o comportamento de executar a próxima declaração ou bloco de declarações, se a condição avaliada seja true
. Um if
pode ser pareado com um else
e assim executar a declaração que o sucede se o valor da condição for false
. Você também pode encadear vários if
, que serão testados um de cada vez. Veja o exemplo:
if (condicao1) console.log('Condição 1 verdadeira');
if (condicao2) {
console.log('Bloco de declarações');
console.log('Condição 2 também verdadeira');
} else console.log('Condição 2 falsa');
if (condicao3) {
console.log('Condição 3 verdadeira');
} else if (condicao4) {
console.log('Condição 3 é falsa e condição 4 verdadeira');
} else {
console.log('Condição 3 e 4 são falsas');
}
Falsy e Truthy 🙝
Nas declarações condicionais, a condição sempre avaliada a expressão em true
ou false
. No entanto, mesmo que a expressão não seja do tipo booleano, o JavaScript, em sua coersão de tipos, trata alguns valores especiais e os avalia como false
quando são utilizados em um contexto booleano. Esses valores são chamados de falsy. São eles:
- Valores indefinidos
undefined
enull
; - Números
0
eNaN
; - String vazia
""
e''
.
Qualquer outro valor da linguagem JavaScript, incluindo objetos, são avaliados como true
e por são chamados de truthy. Por isso é preciso atenção especial com valores primitivos true
e false
e com instâncias de Boolean. Veja o exemplo abaixo:
var p = false;
var o = new Boolean(false);
if (p) console.log('A condição é falsa, pois p é do tipo boolean');
if (o) console.log('A condição é verdadeira pois c é um objeto.');
Condicional múltipla switch … case
🙝
O switch
é uma declaração condicional poderosa e complexa que permite que o desenvolvedor escreva uma expressão de condição combine uma expressão com um valor enumerado. Se houver combinação, o switch
é ativado e executa as declarações que seguem. Sua sintaxe pode ser resumida em:
switch ([expressão]) {
case [expressão1]:
[declaração]
case [expressão2]:
[declaração]
…
default:
[declaração]
}
O switch
possui um mecanismo de fall-through, ou seja, a partir do momento que a expressão combina com um valor, todas as próximas declarações são executadas também. Veja no exemplo abaixo:
var temperatura = 20;
switch (temperatura) {
case 0:
console.log('Temperatura: 0 graus');
case 20:
console.log('Temperatura: 20 graus');
case 30:
console.log('Temperatura: 30 graus');
default:
console.log('Temperatura: acima de 30 graus');
}
var clima = 'Nublado';
switch (clima) {
case 'Sol':
console.log('Hoje está um dia de sol');
case 'Nublado':
console.log('Hoje o céu está nublado');
case 'Chuva':
console.log('Hoje está chuvoso');
default:
console.log('Clima não informado');
}
Podemos ver a saída desse código abaixo:
Temperatura: 20 graus Temperatura: 30 graus Temperatura: acima de 30 graus Hoje o céu está nublado Hoje está chuvoso Clima não informado
O JavaScript, ao se deparar com uma declaração switch
primeiramente avalia a expressão de condição e inicia uma cadeia de busca de rótulos que combinem com a condição. Caso houver combinação, as declarações associadas a ele são executadas. Além disso, o mecanismo de fall-through também é ativado. Assim, todas as declarações abaixo do valor combinado também são executadas, inclusive a declaração default
.
Caso você não queira que o mecanismo de fall-through tenha efeito, você pode utilizar a declaração break
que força a saída do fluxo do switch
. Veja o mesmo código anterior utilizando o break
para cada uma das condições:
var temperatura = 20;
switch (temperatura) {
case 0:
console.log('Temperatura: 0 graus');
break;
case 20:
console.log('Temperatura: 20 graus');
break;
case 30:
console.log('Temperatura: 30 graus');
break;
default:
console.log('Temperatura: acima de 30 graus');
break;
}
var clima = 'Nublado';
switch (clima) {
case 'Sol':
console.log('Hoje está um dia de sol');
break;
case 'Nublado':
console.log('Hoje o céu está nublado');
break;
case 'Chuva':
console.log('Hoje está chuvoso');
break;
default:
console.log('Clima não informado');
break;
}
Que vai ter, como esperado, a saída:
Temperatura: 20 graus Hoje o céu está nublado
Por utilidade, o default
é sempre colocado ao final do bloco, mas não precisa necessariamente ser assim. O efeito colateral de colocar o default
antes do final é que, por ele ativar o mecanismo de fall-through, qualquer declaração abaixo também será executada, o que é raramente desejado.
Declarações de laço 🙝
Declarações de laço são utilizadas para executar código repetido. Há três principais declarações de laço em JavaScript: for
, while
, e do … while
. Também é possível dar rótulos para esses laços e localizá-los através de um nome com as declarações label
, break
e continue
.
Laço condicional simples while
🙝
A declaração while
, a mais simples das declarações de laço, executa a próxima declaração enquanto o valor da expressão avaliada for true
. Se a expressão for false
, o laço para de ser executado e o fluxo segue para a próxima declaração após o laço. A expressão de condição é sempre testada antes das declarações serem executadas. Para fazer laços infinitos, ou seja, laços que nunca param, basta colocar a condição como true
.
Vamos calcular utilizando o while
, veja o código abaixo:
var resultado = 1;
var expoente = 0;
while (expoente < 10) {
resultado = resultado * 2;
expoente++;
}
console.log(resultado); // → 1024
Laço condicional simples do…while
🙝
A declaração do…while
tem um comportamento parecido com o while
: executa uma enquanto uma condição booleana é true
. A diferença entre o while
e o do…while
é a ordem de avaliação da expre ssão da condição em relação a declaração. Enquanto no while
, se a expressão for false
, a declaração não chega nem a ser executada, para o do…while
, a declaração é sempre executada ao menos uma vez, indepentende da expressão ser true
ou false
. Laços infinitos também podem ser feitos bastando colocar a condição como true
.
Usando o mesmo exemplo anterior, vamos calcular utilizando o do … while
, veja o código abaixo:
var resultado = 1;
var expoente = 0;
do {
resultado = resultado * 2;
expoente += 1;
} while (expoente < 10);
console.log(resultado); // → 1024
Laços completos com for
🙝
Um laço for
também repete a próxima declaração até que a condição dada avaliada como false
. Porém, junto com a condição, ela carrega outras duas declarações: a inicialização e o passo. Um for
, ao ser executado, faz os seguintes passos ordenadamente:
- Executa a inicialização
- Se a condição é
true
, executa a declaração correspondente; se forfalse
, sai do laço sem executar a declaração nem o passo; - Executa o passo e volta ao item número 2.
A inicialização é normalmente utilizada para atribuir valores iniciais às variáveis de controle. Já o passo, indica qual o ritmo que o for
deve ter. Lembre-se, como a inicialização e o passo são declarações, podem ser vazias também para criar laços infinitos.
Vamos ver o mesmo exemplo de cálculo de escrito com for
:
var resultado = 1;
for (var expoente = 0; expoente < 10; expoente += 1) {
resultado = resultado * 2;
}
console.log(resultado); // → 1024
Veja que a variável expoente foi declarada na inicialização do laço, e o seu passo é dado de 1 em 1.
Declarações de rótulo e quebra de fluxo 🙝
O JavaScript permite a criação de rótulos que identificam uma declaração. Qualquer declaração pode ser rotulada, porém esse recurso é mais utilizada em laços aninhados. Dessa forma, você pode interromper a execução de laços aninhados específicos de forma declarativa.
Declarações de rótulo 🙝
Declaração de rotulação que marca uma posição em seu código. O rótulo segue as mesmas regras que nomes dados para variáveis. Dada pela sintaxe:
[rótulo]: [declaração]
Quebra de fluxo com break
🙝
Como já vimos no exemplo do switch
, a declaração break
sem um rótulo interrompe a execução da declaração atual. Em caso de laços, a declaração break
faz que o laço atual pare de ser executado imediatamente e continue a execução a partir da próxima declaração após o laço. Podemos utilizar o break
acompanhado de um label
, assim quando execução é interrompida, ela inicia a partir da primeira declaração após o rótulo. Sua sintaxe é simples:
break
break [rótulo]
Quebra de fluxo com continue
🙝
A declaração continue
também quebra o fluxo de execução, mas só pode ser utilizado em laços. Enquanto o break
para a execução do laço, o continue
quebra a atual iteração do laço e inicia uma nova. Ou seja, faz com que a condição seja testada novamente e, no caso do for
, o passo seja executado também. Quando acompanhado de um rótulo, o continue
tem o mesmo comportamento, mas para o laço rotulado. A sintaxe é
continue
continue [rótulo]
O exemplo abaixo é um modo ruim e pouco eficiente de exibir os naturais menores que 100 — mas auxilia a compreensão do continue
e break
junto a um rótulo mostrados.
var j = 0;
lacoExterno: for (var i = 0; ; i += 10) {
j = 0;
if (i >= 100) break lacoExterno;
while (true) {
if (j < 10) {
console.log(j + i);
j++;
} else {
continue lacoExterno;
}
}
}
Conclusão 🙝
Declarações são os blocos de construção da linguagem. Utilizar declarações em sequência dá ao seu código novas maneiras de ser executado, permitindo interferir no fluxo com que as instruções são executadas de acordo com as condições que você desejar. Já os valores, que também são declarações, sempre resultam um valor e podem ser utilizados em variáveis e também em outras declarações.