034.2 Lição 1
Certificação: |
Web Development Essentials |
---|---|
Versão: |
1.0 |
Tópico: |
034 Programação em JavaScript |
Objetivo: |
034.2 Estruturas de dados em JavaScript |
Lição: |
1 de 1 |
Introdução
As linguagens de programação, como as linguagens naturais, representam a realidade por meio de símbolos que são combinados em declarações imbuídas de significado. A realidade representada por uma linguagem de programação são os recursos da máquina, como as operações do processador, os dispositivos e a memória.
Cada uma das muitas linguagens de programação adota um paradigma para representar as informações. O JavaScript utiliza as convenções típicas das linguagens de alto nível, nas quais a maioria dos detalhes, como a alocação de memória, está implícita, permitindo que o programador se concentre na finalidade do script no contexto do aplicativo.
Linguagens de alto nível
Linguagens de alto nível fornecem regras abstratas que permitem ao programador escrever menos código para expressar uma ideia. O JavaScript oferece maneiras convenientes para aproveitar a memória do computador, com conceitos de programação que simplificam a escrita de práticas recorrentes e que geralmente bastam para as finalidades de um desenvolvedor web.
Note
|
Embora seja possível empregar mecanismos especializados para um acesso meticuloso à memória, os tipos mais simples de dados que veremos são de uso mais geral. |
As operações típicas de um aplicativo web consistem em solicitar dados por meio de alguma instrução JavaScript e armazená-los para que sejam processados e, em seguida, apresentados ao usuário. Esse armazenamento é bastante flexível em JavaScript, com formatos adequados a cada finalidade.
Declaração de constantes e variáveis
A declaração de constantes e variáveis para armazenar dados é a pedra angular de qualquer linguagem de programação. O JavaScript adota a convenção da maioria das linguagens de programação, atribuindo valores a constantes ou variáveis com a sintaxe name = value
. A constante ou variável à esquerda assume o valor mostrado à direita. O nome da constante ou variável deve começar com uma letra ou sublinhado (underscore).
O tipo de dados armazenados na variável não precisa ser indicado, pois o JavaScript é uma linguagem de tipagem dinâmica. O tipo da variável é inferido a partir do valor atribuído a ela. Porém, é aconselhável designar certos atributos na declaração para garantir o resultado esperado.
Note
|
O TypeScript é uma linguagem inspirada no JavaScript que, como as linguagens de baixo nível, permite declarar variáveis para tipos específicos de dados. |
Constantes
Uma constante é um símbolo atribuído uma única vez, quando o programa é iniciado, mantendo-se sempre igual. As constantes são úteis para especificar valores fixos, por exemplo a constante PI
como 3,14159265 ou COMPANY_NAME
como o nome de sua empresa.
Assim, por exemplo, em um aplicativo web poderíamos ter um cliente que recebe informações meteorológicas de um servidor remoto. O programador pode decidir que o endereço do servidor deve ser constante, pois ele não mudará durante a execução da aplicação. As informações de temperatura, no entanto, podem ser diferentes a cada chegada de novos dados do servidor.
O intervalo entre as consultas feitas ao servidor também pode ser definido como uma constante, que pode ser consultada de qualquer parte do programa:
const update_interval = 10;
function setup_app(){
console.log("Update every " + update_interval + "minutes");
}
Quando invocada, a função setup_app()
exibe a mensagem Update every 10 minutes
no console. O termo const
, colocado antes do nome update_interval
, garante que seu valor permanecerá o mesmo durante toda a execução do script. Se for feita uma tentativa de redefinir o valor de uma constante, é emitido um erro TypeError: Assignment to constant variable
.
Variáveis
Sem o termo const
, o JavaScript pressupõe automaticamente que update_interval
é uma variável e que seu valor pode ser modificado. Isso equivale a declarar a variável explicitamente com var
:
var update_interval;
update_interval = 10;
function setup_app(){
console.log("Update every " + update_interval + "minutes");
}
Observe que, embora a variável update_interval
tenha sido definida fora da função, ela foi acessada de dentro da função. Qualquer constante ou variável declarada fora de funções ou blocos de código definidos por chaves ({}
) tem escopo global; ou seja, pode ser acessada de qualquer parte do código. O oposto não é verdadeiro: uma constante ou variável declarada dentro de uma função tem escopo local, sendo acessível apenas de dentro da própria função. Os blocos de código delimitados por chaves, como aqueles colocados em estruturas de decisão if
ou loops for
, delimitam o escopo das constantes, mas não das variáveis declaradas como var
. O código a seguir, por exemplo, é válido:
var success = true;
if ( success == true )
{
var message = "Transaction succeeded";
var retry = 0;
}
else
{
var message = "Transaction failed";
var retry = 1;
}
console.log(message);
A declaração console.log(message)
é capaz de acessar a variável message
, mesmo que ela tenha sido declarada dentro do bloco de código da estrutura if
. O mesmo não aconteceria se message
fosse uma constante, conforme exemplificado a seguir:
var success = true;
if ( success == true )
{
const message = "Transaction succeeded";
var retry = 0;
}
else
{
const message = "Transaction failed";
var retry = 1;
}
console.log(message);
Nesse caso, apareceria uma mensagem de erro do tipo ReferenceError: message is not defined
e o script seria interrompido. Embora isso pareça uma limitação, restringir o escopo de variáveis e constantes ajuda a evitar confusão entre as informações processadas no corpo do script e em seus diferentes blocos de código. Por esse motivo, as variáveis declaradas com let
em vez de var
também têm escopo restrito aos blocos delimitados por chaves. Há outras diferenças sutis entre as variáveis declaradas com var
ou let
, mas a mais significativa diz respeito ao escopo da variável, como mostrado aqui.
Tipos de valores
Na maioria das vezes, o programador não precisa se preocupar com o tipo de dados armazenados em uma variável, pois o JavaScript os identifica automaticamente com um de seus tipos primitivos durante a primeira atribuição de um valor à variável. Algumas operações, no entanto, podem ser específicas para um certo tipo de dados e podem resultar em erros quando usadas sem critério. Além disso, o JavaScript oferece tipos estruturados, que permitem combinar mais de um tipo primitivo em um único objeto.
Tipos primitivos
Os tipos primitivos correspondem às variáveis tradicionais, que armazenam apenas um valor. Os tipos são definidos implicitamente, de modo que o operador typeof
pode ser usado para identificar o tipo de valor que é armazenado em uma variável:
console.log("Undefined variables are of type", typeof variable);
{
let variable = true;
console.log("Value `true` is of type " + typeof variable);
}
{
let variable = 3.14159265;
console.log("Value `3.14159265` is of type " + typeof variable);
}
{
let variable = "Text content";
console.log("Value `Text content` is of type " + typeof variable);
}
{
let variable = Symbol();
console.log("A symbol is of type " + typeof variable);
}
Este script exibirá no console o tipo de variável usada em cada caso:
undefined variables are of type undefined Value `true` is of type boolean Value `3.114159265` is of type number Value `Text content` is of type string A symbol is of type symbol
Note que a primeira linha tenta encontrar o tipo de uma variável não declarada. Isso faz com que a variável dada seja identificada como undefined
. O tipo symbol
é o primitivo menos intuitivo. Sua finalidade é fornecer um nome de atributo único dentro de um objeto quando não existir a necessidade de definir um nome de atributo específico. Um objeto é uma das estruturas de dados que veremos a seguir.
Tipos estruturados
Embora os tipos primitivos bastem para escrever rotinas simples, seu uso exclusivo nem sempre é indicado em aplicativos mais complexos. Um aplicativo de comércio eletrônico, por exemplo, seria muito mais difícil de escrever, porque o programador precisaria encontrar maneiras de armazenar listas de itens e seus valores correspondentes usando apenas variáveis com tipos primitivos.
Os tipos estruturados simplificam a tarefa de agrupar informações da mesma natureza em uma única variável. Uma lista de itens em um carrinho de compras, por exemplo, pode ser armazenada em uma única variável do tipo matriz (array):
let cart = ['Milk', 'Bread', 'Eggs'];
Conforme demonstrado no exemplo, uma matriz de itens é designada entre colchetes. O exemplo preencheu a matriz com três valores de string literais, por isso o uso de aspas simples. As variáveis também podem ser usadas como itens em uma matriz, mas nesse caso devem ser designadas sem aspas. O número de itens em uma matriz pode ser consultado com a propriedade length
:
let cart = ['Milk', 'Bread', 'Eggs'];
console.log(cart.length);
O número 3
será exibido na saída do console. Novos itens podem ser adicionados à matriz com o método push()
:
cart.push('Candy');
console.log(cart.length);
Desta vez, a quantidade exibida será 4
. Cada item da lista pode ser acessado por seu índice numérico, começando com 0
:
console.log(cart[0]);
console.log(cart[3]);
A saída exibida no console será:
Milk Candy
Assim como se pode usar push()
para adicionar um elemento, usamos pop()
para remover o último elemento de uma matriz.
Os valores armazenados em uma matriz não precisam ser do mesmo tipo. É possível, por exemplo, armazenar a quantidade de cada item ao lado dele. Uma lista de compras como a do exemplo anterior pode ser construída da seguinte forma:
let cart = ['Milk', 1, 'Bread', 4, 'Eggs', 12, 'Candy', 2];
// Item indexes are even
let item = 2;
// Quantities indexes are odd
let quantity = 3;
console.log("Item: " + cart[item]);
console.log("Quantity: " + cart[quantity]);
A saída exibida no console após a execução deste código é:
Item: Bread Quantity: 4
Como você já deve ter notado, combinar os nomes dos itens com suas respectivas quantidades em uma única matriz pode não ser uma boa ideia, porque a relação entre eles não é explícita na estrutura de dados e é muito suscetível a erros (humanos). Mesmo se usássemos uma matriz para os nomes e outra para as quantidades, manter a integridade da lista exigiria o mesmo cuidado e não seria muito produtivo. Nessas situações, a melhor alternativa é usar uma estrutura de dados mais apropriada: um objeto.
No JavaScript, uma estrutura de dados de tipo objeto permite vincular propriedades a uma variável. Além disso, ao contrário de uma matriz, os elementos que constituem um objeto não têm uma ordem fixa. Um item de lista de compras, por exemplo, pode ser um objeto com as propriedades name
e quantity
(nome e quantidade):
let item = { name: 'Milk', quantity: 1 };
console.log("Item: " + item.name);
console.log("Quantity: " + item.quantity);
Este exemplo mostra que um objeto pode ser definido usando chaves ({}
), onde cada par de propriedade/valor é separado por dois pontos e as propriedades são separadas por vírgulas. A propriedade está acessível no formato variable.property, como em item.name
, tanto para leitura quanto para atribuição de novos valores. A saída exibida no console após a execução deste código é:
Item: Milk Quantity: 1
Finalmente, cada objeto que representa um item pode ser incluído na matriz da lista de compras. Isso pode ser feito diretamente ao se criar a lista:
let cart = [{ name: 'Milk', quantity: 1 }, { name: 'Bread', quantity: 4 }];
Como anteriormente, um novo objeto que representa um item pode ser adicionado posteriormente à matriz:
cart.push({ name: 'Eggs', quantity: 12 });
Os itens na lista agora podem ser acessados por seu índice e seu nome de propriedade:
console.log("Third item: " + cart[2].name);
console.log(cart[2].name + " quantity: " + cart[2].quantity);
A saída exibida no console após a execução deste código é:
third item: eggs Eggs quantity: 12
As estruturas de dados permitem que o programador mantenha o código muito mais organizado e fácil de manter, seja pelo autor original ou por outros programadores da equipe. Além disso, muitas saídas de funções JavaScript estão em tipos estruturados, que precisam ser manipulados adequadamente pelo programador.
Operadores
Até aqui, praticamente apenas vimos como atribuir valores a variáveis recém-criadas. Qualquer programa, por mais simples que seja, realizará diversas outras manipulações nos valores das variáveis. O JavaScript oferece muitos tipos de operadores capazes de atuar diretamente no valor de uma variável ou armazenar o resultado da operação em uma nova variável.
A maioria dos operadores é orientada para operações aritméticas. Para aumentar a quantidade de um item na lista de compras, por exemplo, basta usar o operador de adição +
:
item.quantity = item.quantity + 1;
O trecho de código a seguir imprime o valor de item.quantity
antes e depois da adição. Não confunda as funções do sinal de mais no trecho. As declarações console.log
usam um sinal de mais para combinar duas strings.
let item = { name: 'Milk', quantity: 1 };
console.log("Item: " + item.name);
console.log("Quantity: " + item.quantity);
item.quantity = item.quantity + 1;
console.log("New quantity: " + item.quantity);
A saída exibida no console após a execução deste código é:
Item: Milk Quantity: 1 New quantity: 2
Observe que o valor anteriormente armazenado em item.quantity
é usado como operando da operação de adição: item.quantity = item.quantity + 1
. Somente após a conclusão da operação, o valor em item.quantity
é atualizado com o resultado. Esse tipo de operação aritmética envolvendo o valor atual da variável de destino é bastante comum, e assim existem operadores abreviados que permitem escrever a mesma operação em um formato reduzido:
item.quantity += 1;
As outras operações básicas também têm operadores abreviados equivalentes:
-
a = a - b
equivale aa -= b
. -
a = a * b
equivale aa *= b
. -
a = a / b
equivale aa /= b
.
Para adição e subtração, existe um terceiro formato disponível quando o segundo operando é apenas uma unidade:
-
a = a + 1
equivale aa++
. -
a = a - 1
equivale aa--
.
É possível combinar mais de um operador na mesma operação e armazenar o resultado em uma nova variável. Por exemplo, a seguinte declaração calcula o preço total de um item mais o custo de envio:
let total = item.quantity * 9.99 + 3.15;
A ordem em que as operações são realizadas segue a ordem tradicional de precedência: primeiro são feitas as operações de multiplicação e divisão e em seguida as operações de adição e subtração. Os operadores com a mesma precedência são executados na ordem em que aparecem na expressão, da esquerda para a direita. Para substituir a ordem de precedência padrão, podemos usar parênteses, como em a * (b + c)
.
Em algumas situações, o resultado de uma operação nem precisa ser armazenado em uma variável. Esse é o caso quando queremos avaliar o resultado de uma expressão dentro de uma instrução if
:
if ( item.quantiy % 2 == 0 )
{
console.log("Quantity for the item is even");
}
else
{
console.log("Quantity for the item is odd");
}
O operador %
(módulo) retorna o restante da divisão do primeiro operando pelo segundo operando. No exemplo, a instrução if
verifica se o resto da divisão de item.quantity
por 2
é igual a zero, ou seja, se item.quantity
é um múltiplo de 2.
Quando um dos operandos do operador +
é uma string, os outros operadores sofrem uma coerção em strings e o resultado é uma concatenação de strings. Nos exemplos anteriores, esse tipo de operação foi usado para concatenar strings e variáveis no argumento da declaração console.log
.
Essa conversão automática pode não ser o comportamento desejado. Um valor fornecido pelo usuário em um campo de formulário, por exemplo, pode ser identificado como uma string, mas na verdade é um valor numérico. Em casos como esse, a variável deve primeiro ser convertida em um número com a função Number()
:
sum = Number(value1) + value2;
Além disso, é importante verificar se o usuário forneceu um valor válido antes de prosseguir com a operação. Em JavaScript, uma variável sem um valor atribuído contém o valor null
. Isso permite que o programador use uma declaração de decisão como if (value1 == null)
para verificar se uma variável teve um valor atribuído, independentemente do tipo de valor atribuído à variável.
Exercícios Guiados
-
Um array (matriz) é uma estrutura de dados presente em várias linguagens de programação, das quais algumas permitem apenas matrizes com itens do mesmo tipo. No caso do JavaScript, é possível definir uma matriz com itens de tipos diferentes?
-
Com base no exemplo
let item = { name: 'Milk', quantity: 1 }
para um objeto em uma lista de compras, como esse objeto poderia ser declarado de forma a incluir o preço do item? -
Em uma única linha de código, quais são as maneiras de atualizar o valor de uma variável para a metade de seu valor atual?
Exercícios Exploratórios
-
No código a seguir, qual valor será exibido na saída do console?
var value = "Global"; { value = "Location"; } console.log(value);
-
O que acontece quando um ou mais operandos envolvidos em uma operação de multiplicação é uma string?
-
Como é possível remover o item
Eggs
da matrizcart
declarada comlet cart = ['Milk', 'Bread', 'Eggs']
?
Resumo
Esta lição cobre o uso básico de constantes e variáveis em JavaScript. O JavaScript é uma linguagem de tipagem dinâmica; assim, o programador não precisa especificar o tipo de variável antes de defini-lo. No entanto, é importante conhecer os tipos primitivos da linguagem para garantir o resultado correto das operações básicas. Além disso, estruturas de dados como matrizes e objetos combinam tipos primitivos e permitem ao programador construir variáveis compostas mais complexas. Esta lição aborda os seguintes conceitos e procedimentos:
-
Compreender constantes e variáveis
-
Escopo de uma variável
-
Declaração de variáveis com
var
elet
-
Tipos primitivos
-
Operadores aritméticos
-
Matrizes e objetos
-
Coerção e conversão de tipo
Respostas aos Exercícios Guiados
-
Um array (matriz) é uma estrutura de dados presente em várias linguagens de programação, das quais algumas permitem apenas matrizes com itens do mesmo tipo. No caso do JavaScript, é possível definir uma matriz com itens de tipos diferentes?
Sim, em JavaScript é possível definir matrizes com itens de diferentes tipos primitivos, como strings e números.
-
Com base no exemplo
let item = { name: 'Milk', quantity: 1 }
para um objeto em uma lista de compras, como esse objeto poderia ser declarado de forma a incluir o preço do item?let item = { name: 'Milk', quantity: 1, price: 4.99 };
-
Em uma única linha de código, quais são as maneiras de atualizar o valor de uma variável para a metade de seu valor atual?
Pode-se usar a própria variável como um operando,
value = value / 2
, ou o operador abreviado/=
:value /= 2
.
Respostas aos Exercícios Exploratórios
-
No código a seguir, qual valor será exibido na saída do console?
var value = "Global"; { value = "Location"; } console.log(value);
Location
-
O que acontece quando um ou mais operandos envolvidos em uma operação de multiplicação é uma string?
O JavaScript atribuirá o valor
NaN
(Not a Number) ao resultado, indicando que a operação é inválida. -
Como é possível remover o item
Eggs
da matrizcart
declarada comlet cart = ['Milk', 'Bread', 'Eggs']
?As matrizes em Javascript incluem o método
pop()
, que remove o último item da lista:cart.pop()
.