Nesta revisão, abordaremos os principais conceitos de JavaScript, incluindo tipos de dados, variáveis, operadores, estruturas condicionais e de repetição. Vamos explorar também funções, objetos, arrays, e técnicas como hoisting e escopo. O objetivo é fornecer uma visão prática e objetiva dos fundamentos essenciais para o desenvolvimento em JavaScript.
- O que é uma linguagem de programação
- Tipos de dados
- Variáveis
- Hoisting
- Operadores e Expressões
- Expressões
- Comentários
- Usando JavaScript no HTML
- Comparação de dados
- Operadores lógicos
- Estruturas condicionais: If e Else
- Estruturas Condicionais: Switch
- Estruturas de Repetição
- Estruturas de dados
- Arrays
- Objetos
- Funções
- Escopo
- Métodos
- Funções Recursivas
- Funções Anônimas
- High-order Functions
- Objetos Globais
- Eventos, DOM e Manipulação em JavaScript
Uma linguagem de programação é um método padronizado de comunicação entre programadores e computadores. É um sistema formal composto por um conjunto de regras sintáticas e semânticas que permitem a criação de código fonte. Este código fonte pode ser compilado e transformado em um programa de computador ou interpretado como um script .As linguagens de programação permitem que os programadores especifiquem com precisão:
- Quais dados o computador irá processar
- Como esses dados serão armazenados ou transmitidos
- Quais ações devem ser tomadas sob diversas circunstâncias
Além disso, as linguagens de programação são usadas para expressar algoritmos com precisão. O conjunto de palavras (lexemas classificados em tokens) que compõem o código fonte de um software é construído de acordo com as regras específicas da linguagem utilizada.As linguagens de programação servem como uma ponte entre o pensamento humano e a execução da máquina. Elas consistem em um conjunto de instruções que, quando escritas corretamente, podem ser convertidas em código de máquina ou, no caso de linguagens visuais, em elementos gráficos.
JavaScript, frequentemente abreviado como JS, é uma linguagem de programação de alto nível, interpretada e multiparadigma. Ela foi originalmente criada para funcionar no lado do cliente, ou seja, nos navegadores web, mas atualmente também é utilizada em ambientes de servidor .Características principais do JavaScript:
- Linguagem de script: Permite a criação de conteúdo dinâmico e interativo em páginas web.
- Interpretada: O código é executado diretamente, sem necessidade de compilação prévia.
- Tipagem dinâmica: Os tipos de variáveis são determinados em tempo de execução.
- Multiparadigma: Suporta programação orientada a objetos, imperativa e funcional.
- Essencial para a web moderna: Junto com HTML e CSS, é uma das principais tecnologias da World Wide Web.
O JavaScript permite:
- Controlar elementos de uma página em tempo real
- Atualizar conteúdo sem recarregar a página completa
- Interagir com o usuário de forma dinâmica
- Enviar e receber dados do servidor de maneira assíncrona
É importante notar que, apesar do nome similar, JavaScript não é uma variante do Java. São linguagens distintas com propósitos diferentes
JavaScript é uma linguagem de tipagem dinâmica, o que significa que o tipo de uma variável é determinado automaticamente com base no valor atribuído a ela. Os principais tipos de dados em JavaScript são:
- Number: Representa valores numéricos, tanto inteiros quanto de ponto flutuante.Exemplo:
let idade = 30;
oulet altura = 1.75;
- - String: Representa sequências de caracteres, delimitadas por aspas simples ou duplas.Exemplo:
let nome = "João";
oulet mensagem = 'Olá, mundo!';
- Boolean: Representa valores lógicos verdadeiro (true) ou falso (false).Exemplo:
let aprovado = true;
- Undefined: Indica que uma variável foi declarada, mas não foi atribuído nenhum valor a ela.Exemplo:
let variavelNaoInicializada;
- Null: Representa a ausência intencional de qualquer valor ou objeto.Exemplo:
let valorNulo = null;
- Object: Estrutura de dados complexa que pode conter múltiplas propriedades e métodos.Exemplo:
let pessoa = {nome: "Maria", idade: 25};
- Array: Um tipo especial de objeto usado para armazenar listas ordenadas de valores.Exemplo:
let frutas = ["maçã", "banana", "laranja"];
- Function: Bloco de código reutilizável que pode ser chamado para executar tarefas específicas.Exemplo:
function somar(a, b) { return a + b; }
- Symbol: Tipo de dado introduzido no ECMAScript 6, representa um identificador único.Exemplo:
let simbolo = Symbol("descricao");
Além desses tipos básicos, JavaScript também suporta outros tipos de dados mais avançados e estruturas de controle que permitem a criação de programas complexos e interativos
Variáveis em JavaScript são contêineres para armazenar dados. Elas são fundamentais para qualquer programa, pois permitem armazenar e manipular informações durante a execução do código.
Em JavaScript moderno (ES6+), existem três formas de declarar variáveis:
let
: Usado para declarar variáveis que podem ter seu valor alterado.javascriptlet idade = 25; idade = 26; // Valor pode ser alterado
const
: Usado para declarar constantes, cujo valor não pode ser alterado após a atribuição inicial.const PI = 3.14159; PI = 3.14; // Isso causaria um erro
var
: Forma mais antiga de declarar variáveis, com escopo de função ou global.var nome = "João";
- Devem começar com uma letra, underscore (_) ou cifrão ($).
- Podem conter letras, números, underscores e cifrões.
- São case-sensitive (maiúsculas e minúsculas são diferentes).
- Não podem ser palavras reservadas do JavaScript.
let
econst
possuem escopo de bloco. Isso significa que elas estão disponíveis apenas dentro do bloco onde foram declaradas, delimitado por{}
.var
possui escopo de função ou global, ou seja, está disponível dentro de toda a função onde foi declarada, mesmo que a declaração esteja em um bloco interno. Se declarada fora de uma função, torna-se global.
{
let x = 10; // x só existe dentro deste bloco
}
console.log(x); // Isso causaria um erro, pois x não está definido fora do bloco
function exemplo() {
var y = 20; // y existe em toda a função
}
console.log(y); // Isso também causaria um erro, pois y não está definido fora da função
É o comportamento do JavaScript de mover as declarações de variáveis e funções para o topo de seu escopo antes da execução do código.
- Variáveis declaradas com
var
são "elevadas" (hoisted) para o topo do escopo, mas são inicializadas com o valorundefined
até que uma atribuição explícita ocorra no código. - Variáveis declaradas com
let
econst
também são "elevadas", mas permanecem em um estado de temporal dead zone (TDZ) até que sua declaração seja executada. Isso significa que elas não podem ser acessadas antes de sua inicialização.
console.log(a); // undefined
var a = 5; // A variável é elevada e inicializada com undefined, depois recebe o valor 5
// console.log(b); // Erro: Cannot access 'b' before initialization
let b = 10; // A variável é elevada, mas permanece na temporal dead zone até esta linha
var
:
- É inicializada como
undefined
durante o hoisting. - Pode ser acessada antes da linha de declaração sem causar erro, mas o valor será
undefined
.
console.log(x); // undefined
var x = 10;
let
:
- É elevada, mas não é inicializada até que a execução alcance sua declaração.
- Tentativas de acesso antes da inicialização resultam em um erro.
console.log(y); // Erro: Cannot access 'y' before initialization
let y = 20;
const
:
- Comporta-se de maneira semelhante ao
let
, mas, além disso, exige a inicialização no momento da declaração.
console.log(z); // Erro: Cannot access 'z' before initialization
const z = 30;
- Prefira
let
e const
ao invés devar
para evitar problemas causados pelo hoisting e pela inicialização automática de variáveis. - Sempre declare variáveis antes de usá-las para melhorar a legibilidade e evitar confusões.
Declarações de funções (function
) também são elevadas, permitindo que sejam chamadas antes de serem declaradas.
sayHello(); // "Hello, world!"
function sayHello() {
console.log("Hello, world!");
}
- Funções atribuídas a variáveis, como no caso de funções anônimas ou arrow functions, seguem o comportamento do hoisting da variável usada:
// sayHi(); // Erro: Cannot access 'sayHi' before initialization
const sayHi = () => console.log("Hi!");
Operadores em JavaScript são símbolos especiais que realizam operações específicas em operandos. Expressões são combinações de valores, variáveis e operadores que são avaliadas para produzir um resultado.
Os operadores aritméticos são utilizados para realizar cálculos matemáticos.
- Adição (+): Soma dois valores.
let soma = 5 + 3; // 8
- Subtração (-): Subtrai o segundo valor do primeiro.
let diferenca = 10 - 4; // 6
- Multiplicação (*): Multiplica dois valores.
let produto = 3 * 4; // 12
- Divisão (/): Divide o primeiro valor pelo segundo.
let quociente = 20 / 5; // 4
- Módulo (%): Retorna o resto da divisão do primeiro valor pelo segundo.
let resto = 17 % 3; // 2
- Incremento (++): Aumenta o valor de uma variável em 1.
let x = 5;
x++; // x agora é 6
- Decremento (--): Reduz o valor de uma variável em 1.
let y = 8;
y--; // y agora é 7
- Exponenciação ()**: Eleva o primeiro valor à potência do segundo.
let potencia = 2 ** 3; // 8
Os operadores de atribuição atribuem valores às variáveis.
- Atribuição simples (=): Atribui um valor à variável.
let x = 5;
- Atribuição com adição (+=): Soma o valor atual ao novo valor e atualiza a variável.
x += 3; // equivalente a x = x + 3
- Atribuição com subtração (-=): Subtrai o valor do novo valor e atualiza a variável.
x -= 2; // equivalente a x = x - 2
- Atribuição com multiplicação (*=): Multiplica o valor atual pelo novo valor e atualiza a variável.
x *= 4; // equivalente a x = x * 4
- Atribuição com divisão (/=): Divide o valor atual pelo novo valor e atualiza a variável.
x /= 2; // equivalente a x = x / 2
Usados para comparar dois valores, retornando true ou false.
- Igual (==): Compara apenas o valor, ignorando o tipo.
5 == "5"; // true
- Estritamente igual (===): Compara valor e tipo.
5 === "5"; // false
- Diferente (!=): Retorna true se os valores forem diferentes, ignorando o tipo.
5 != "6"; // true
- Estritamente diferente (!==): Retorna true se valores e tipos forem diferentes.
5 !== "5"; // true
- Maior que (>):
10 > 5; // true
- Menor que (<):
3 < 7; // true
- Maior ou igual (>=):
5 >= 5; // true
- Menor ou igual (<=):
4 <= 4; // true
Usados para combinar ou inverter condições lógicas.
- AND (&&): Retorna true se ambas as condições forem verdadeiras.
true && false; // false
- OR (||): Retorna true se pelo menos uma das condições for verdadeira.
true || false; // true
- NOT (!): Inverte o valor lógico.
!true; // false
- Concatenação (+): Junta duas ou mais strings.
"Olá" + " " + "Mundo"; // "Olá Mundo"
O operador ternário é uma forma concisa de escrever um if/else.
- Sintaxe:
condição ? expressão1 : expressão2
Exemplo:
let idade = 20;
let status = idade >= 18 ? "Adulto" : "Menor"; // "Adulto"
typeof
: Retorna o tipo do valor.
typeof 42; // "number"
typeof "Olá"; // "string"
instanceof
: Verifica se um objeto pertence a uma classe ou protótipo.
[1, 2] instanceof Array; // true
Expressões são combinações de valores, variáveis e operadores que são avaliadas para produzir um resultado. Elas podem ser simples ou complexas.Exemplos de expressões:
let x = 5;
let y = 3;
let z = x + y * 2; // 11
let nome = "Alice";
let saudacao = "Olá, " + nome + "!"; // "Olá, Alice!"
let maiorIdade = idade >= 18;
let resultado = (x > y) ? "x é maior" : "y é maior ou igual";
Comentários são trechos de texto no código que são ignorados pelo interpretador JavaScript. Eles são usados para explicar o código, fazer anotações ou desabilitar temporariamente partes do código.
-
Comentários de Linha Única
- Começam com // e continuam até o final da linha.
// Este é um comentário de linha única let x = 5; // Isso também é um comentário de linha única
-
Comentários de Múltiplas Linhas
- Começam com /* e terminam com */.
- Podem abranger várias linhas.
/* Este é um comentário de múltiplas linhas. Pode ocupar várias linhas. */
-
Use comentários para explicar o "porquê" e não o "como".
// Calcula a idade em anos bissextos function calcularIdadeBissexto(anoNascimento) { // Código aqui }
-
Mantenha os comentários atualizados quando o código mudar.
-
Evite comentários óbvios que não agregam valor.
// Ruim let x = 5; // Atribui 5 a x // Bom let velocidadeInicial = 5; // Em metros por segundo
-
Use comentários para documentar funções complexas.
/* * Calcula o fatorial de um número. * @param {number} n - O número para calcular o fatorial. * @returns {number} O fatorial de n. */ function fatorial(n) { // Código aqui }
-
Use comentários para marcar TODO's ou FIXME's.
// TODO: Implementar validação de entrada function processarDados(dados) { // Código aqui } // FIXME: Corrigir bug de arredondamento function calcularMedia(numeros) { // Código aqui }
-
Em ambientes de desenvolvimento, você pode usar comentários para desabilitar temporariamente código.
// let debugMode = true; let debugMode = false;
Lembre-se, código bem escrito muitas vezes é autoexplicativo. Use comentários para adicionar clareza quando necessário, mas não substitua um bom design de código por comentários excessivos.
Existem três principais formas de incluir JavaScript em uma página HTML:
-
Inline: Inserindo código JavaScript diretamente em atributos HTML.
<button onclick="alert('Olá, mundo!')">Clique aqui</button>
-
Interno: Usando a tag
<script>
dentro do documento HTML.<script> function saudacao() { alert('Olá, mundo!'); } </script>
-
Externo: Vinculando um arquivo JavaScript separado.
<script src="meu-script.js"></script>
A abordagem recomendada é usar arquivos JavaScript externos, pois isso melhora a organização do código, permite reutilização e facilita a manutenção.Para otimizar o carregamento, é geralmente recomendado colocar as tags <script>
antes do fechamento da tag </body>
. Isso permite que o conteúdo HTML seja carregado antes da execução dos scripts.
Os navegadores modernos oferecem uma variedade de APIs nativas que podem ser acessadas via JavaScript:
- DOM (Document Object Model): Permite manipular a estrutura, conteúdo e estilos de uma página web.
- Web Storage: Inclui localStorage e sessionStorage para armazenamento de dados no navegador.
- Fetch API: Facilita a realização de requisições HTTP assíncronas.
- Canvas e WebGL: Permitem criar gráficos 2D e 3D diretamente no navegador.
- Geolocation API: Fornece acesso à localização geográfica do usuário.
- Web Audio API: Permite manipular e criar áudio no navegador.
- WebSockets: Possibilita comunicação bidirecional em tempo real.
Essas APIs nativas oferecem funcionalidades poderosas sem a necessidade de bibliotecas externas, permitindo criar aplicações web ricas e interativas.
JavaScript oferece operadores de comparação para avaliar e comparar valores:
-
Igualdade (==): Compara valores, realizando coerção de tipos.
5 == "5" // true
-
Igualdade estrita (===): Compara valores e tipos.
5 === "5" // false
-
Desigualdade (!=): Verifica se os valores são diferentes.
5 != "6" // true
-
Desigualdade estrita (!==): Verifica se os valores ou tipos são diferentes.
5 !== "5" // true
-
Maior que (>), Menor que (<), Maior ou igual (>=), Menor ou igual (<=):
10 > 5 // true 3 < 7 // true 5 >= 5 // true 4 <= 4 // true
É geralmente recomendado usar a igualdade estrita (===) para evitar resultados inesperados devido à coerção de tipos.
JavaScript possui três operadores lógicos principais:
-
AND (&&): Retorna true se ambos os operandos forem verdadeiros.
true && false // false true && true // true
-
OR (||): Retorna true se pelo menos um dos operandos for verdadeiro.
true || false // true false || false // false
-
NOT (!): Inverte o valor booleano.
!true // false !false // true
Estes operadores são frequentemente usados em estruturas de controle de fluxo, como condicionais if-else, e em expressões de avaliação curta-circuito.
let x = 5;
let y = 10;
if (x > 0 && y < 20) {
console.log("Ambas as condições são verdadeiras");
}
Explicação:
- O código verifica duas condições usando o operador lógico AND (&&): -- x > 0 → Verifica se x é maior que 0. (Verdadeiro, pois x = 5) -- y < 20 → Verifica se y é menor que 20. (Verdadeiro, pois y = 10) -Como ambas as condições são verdadeiras, o bloco dentro do if é executado, exibindo a mensagem: "Ambas as condições são verdadeiras" no console.
Os operadores lógicos em JavaScript também exibem o comportamento de curto-circuito, onde a avaliação para assim que o resultado é determinado, o que pode ser útil para verificações condicionais eficientes.
As estruturas condicionais if e else permitem que o código execute diferentes blocos dependendo de condições específicas.
A estrutura if executa um bloco de código se uma condição for verdadeira. Sintaxe:
if (condição) {
// código a ser executado se a condição for verdadeira
}
Exemplo:
let idade = 18;
if (idade >= 18) {
console.log("Você é maior de idade.");
}
A estrutura if...else permite executar um bloco de código se a condição for verdadeira e outro bloco se for falsa. Sintaxe:
if (condição) {
// código a ser executado se a condição for verdadeira
} else {
// código a ser executado se a condição for falsa
}
Exemplo:
let hora = 20;
if (hora < 18) {
console.log("Bom dia!");
} else {
console.log("Boa noite!");
}
Para múltiplas condições, podemos usar else if. Sintaxe:
if (condição1) {
// código se condição1 for verdadeira
} else if (condição2) {
// código se condição2 for verdadeira
} else {
// código se todas as condições anteriores forem falsas
}
Exemplo:
let nota = 75;
if (nota >= 90) {
console.log("A");
} else if (nota >= 80) {
console.log("B");
} else if (nota >= 70) {
console.log("C");
} else {
console.log("D");
}
A estrutura switch
é usada para executar diferentes blocos de código com base no valor de uma expressão. É uma alternativa ao if...else if...else
quando há múltiplas condições relacionadas ao mesmo valor.
Sintaxe:
switch (expressão) {
case valor1:
// código a ser executado
break;
case valor2:
// código a ser executado
break;
...
default:
// código a ser executado se nenhum caso corresponder
}
Exemplo:
let diaDaSemana = 3;
switch (diaDaSemana) {
case 1:
console.log("Segunda-feira");
break;
case 2:
console.log("Terça-feira");
break;
case 3:
console.log("Quarta-feira");
break;
case 4:
console.log("Quinta-feira");
break;
case 5:
console.log("Sexta-feira");
break;
case 6:
case 7:
console.log("Fim de semana");
break;
default:
console.log("Dia inválido");
}
Explicação
switch (diaDaSemana)
- A expressão
diaDaSemana
é avaliada. Seu valor será comparado sequencialmente com os valores definidos emcase
.
case 1
- Se
diaDaSemana
for igual a 1, a mensagem"Segunda-feira"
será exibida no console e a instruçãobreak
encerrará oswitch
.
break
- Impede que o código continue executando outros casos após encontrar uma correspondência. Sem
break
, os blocos seguintes seriam executados, independentemente da correspondência.
Casos compartilhados (case 6:
e case 7:
)
- Se
diaDaSemana
for 6 ou 7, a mensagem"Fim de semana"
será exibida. - Isso ocorre porque ambos os casos compartilham o mesmo bloco de código.
default
- Se nenhum dos casos corresponder ao valor de
diaDaSemana
, o blocodefault
será executado. - Neste exemplo,
"Dia inválido"
será exibido sediaDaSemana
não corresponder a nenhum valor entre 1 e 7.
As estruturas de repetição permitem executar um bloco de código várias vezes, enquanto uma condição específica for verdadeira ou por um número determinado de iterações. Elas são úteis para automatizar tarefas repetitivas e processar conjuntos de dados de forma eficiente. Exemplos comuns incluem for
, while
e do...while
.
O loop while executa um bloco de código enquanto uma condição específica for verdadeira. Sintaxe:
while (condição) {
// código a ser executado
}
Exemplo:
let contador = 0;
while (contador < 5) {
console.log("Contagem: " + contador);
contador++;
}
Explicação:
- O loop inicia verificando se a condição contador < 5 é verdadeira.
- Enquanto for verdadeira, o código dentro do bloco será executado.
- A variável contador é incrementada em 1 a cada iteração.
- Quando a condição se torna falsa, o loop é encerrado.
O loop do...while é similar ao while, mas garante que o bloco de código seja executado pelo menos uma vez antes de verificar a condição.Sintaxe:
do {
// código a ser executado
} while (condição);
Exemplo:
let i = 0;
do {
console.log("O número é " + i);
i++;
} while (i < 5);
Explicação:
- O bloco de código dentro de do é executado uma vez antes de verificar a condição.
- Após a execução inicial, a condição i < 5 é avaliada.
- Enquanto a condição for verdadeira, o código continuará sendo executado.
- Quando a condição se torna falsa, o loop é encerrado.
O loop for é usado quando se sabe antecipadamente quantas vezes o bloco de código deve ser executado.Sintaxe:
for (inicialização; condição; incremento) {
// código a ser executado
}
Exemplo:
for (let i = 0; i < 5; i++) {
console.log("O número é " + i);
}
Explicação:
- A inicialização (
let i = 0
) define o valor inicial da variáveli
. - A condição (
i < 5
) é verificada antes de cada iteração. Enquanto for verdadeira, o código continuará a ser executado. - O incremento (
i++
) aumenta o valor dei
a cada iteração. - O código dentro do bloco do
for
é executado enquanto a condição for verdadeira. Neste caso, ele exibe os números de 0 a 4.
JavaScript suporta várias estruturas de dados nativas. As mais comuns são:
Arrays: Coleções ordenadas de valores.
Arrays são estruturas de dados que armazenam uma lista ordenada de valores. Podem armazenar qualquer tipo de dado e têm um índice numérico para acessar os elementos.
let frutas = ["maçã", "banana", "laranja"];
console.log(frutas[0]); // "maçã"
frutas[0]
acessa o primeiro elemento do array, que é"maçã"
.
Objetos: Coleções de pares chave-valor.
Objetos armazenam dados em pares chave-valor, onde as chaves são únicas e podem ser usadas para acessar seus valores.
let pessoa = {
nome: "João",
idade: 30,
profissao: "Desenvolvedor"
};
console.log(pessoa.nome); // "João"
pessoa.nome
acessa o valor associado à chave"nome"
, que é"João"
.
Map: Coleção de pares chave-valor onde as chaves podem ser de qualquer tipo.
Diferente dos objetos, as chaves de um Map
podem ser de qualquer tipo (não apenas strings ou símbolos). Map
mantém a ordem de inserção dos elementos.
let mapa = new Map();
mapa.set("chave", "valor");
console.log(mapa.get("chave")); // "valor"
mapa.get("chave")
acessa o valor associado à chave"chave"
, que é"valor"
.
- Set: Coleção de valores únicos.
Um Set
é uma coleção de valores únicos, ou seja, não permite valores duplicados.
let conjunto = new Set([1, 2, 3, 3, 4]);
console.log(conjunto.size); // 4
conjunto.size
retorna o número de elementos únicos no conjunto, que é4
, ignorando o valor duplicado3
.
- WeakMap e WeakSet: Versões "fracas" de Map e Set que permitem que suas chaves sejam coletadas pelo garbage collector.
-
WeakMap: Armazena pares chave-valor, mas as chaves são objetos e podem ser coletadas pelo garbage collector quando não houver mais referências.
-
WeakSet: Semelhante ao Set, mas armazena apenas objetos e as referências podem ser coletadas pelo garbage collector quando não houver mais referências.
Exemplo de uso do WeakMap
:
let obj = {};
let weakMapa = new WeakMap();
weakMapa.set(obj, "valor");
console.log(weakMapa.get(obj)); // "valor"
- Se
obj
não tiver mais referências, a chave será coletada pelo garbage collector automaticamente.
Estas estruturas de dados oferecem diferentes maneiras de organizar e manipular dados em JavaScript, cada uma com suas próprias características e casos de uso específicos.
Exemplo de uso do WeakSet
:
let obj1 = {};
let obj2 = {};
let weakSet = new WeakSet();
weakSet.add(obj1);
weakSet.add(obj2);
console.log(weakSet.has(obj1)); // true
console.log(weakSet.has(obj2)); // true
obj1 = null; // O objeto será removido do WeakSet automaticamente pelo garbage collector
- No caso do
WeakSet
, as referências a objetos podem ser removidas automaticamente quando não houver mais referências a eles, o que não ocorre com oSet
comum.
Arrays em JavaScript são estruturas de dados que permitem armazenar múltiplos valores em uma única variável. Eles são objetos que contêm valores (de qualquer tipo) em posições numeradas. Arrays são muito úteis quando se deseja trabalhar com listas de dados de maneira organizada e eficiente.
-
Usando colchetes (forma literal):
- Esta é a forma mais comum e conveniente de criar um array, usando colchetes para definir os elementos diretamente.
let frutas = ["maçã", "banana", "laranja"];
- Os elementos do array são definidos dentro dos colchetes e separados por vírgulas. Essa forma de criação é simples e direta.
-
Usando o construtor Array():
- O construtor
Array()
pode ser usado para criar arrays, mas é menos comum e pode ser um pouco mais confuso quando usado com um único número como argumento.
let numeros = new Array(1, 2, 3, 4, 5);
- Quando utilizado desta forma, o construtor cria um array contendo os valores passados como argumentos. Porém, se for passado um único número como argumento, ele cria um array com esse número de posições vazias.
let vazio = new Array(3); // Cria um array de 3 posições vazias
- O construtor
-
Array vazio:
- Você também pode criar um array sem elementos, o que pode ser útil quando você precisa adicionar elementos dinamicamente mais tarde.
let arrayVazio = [];
- Este método cria um array vazio, pronto para ser preenchido com dados posteriormente.
-
Indexação baseada em zero:
- O primeiro elemento de um array em JavaScript está sempre no índice 0. Isso significa que os índices começam em 0, não 1.
console.log(frutas[0]); // "maçã"
- Se você acessar o índice 0 do array
frutas
, obterá o primeiro elemento, que neste caso é "maçã". Os índices continuam incrementando de 1 para os próximos elementos.
-
Propriedade
length
:- A propriedade
length
retorna o número total de elementos no array, sendo uma forma útil para determinar o tamanho do array e para usá-lo em loops.
console.log(frutas.length); // 3
- Mesmo que o array contenha elementos vazios ou indefinidos, a propriedade
length
contará essas posições vazias. No exemplo acima, o arrayfrutas
tem 3 elementos, entãofrutas.length
retorna 3.
- A propriedade
-
Arrays podem conter diferentes tipos de dados:
- Arrays em JavaScript são muito flexíveis, permitindo armazenar diferentes tipos de dados dentro de um mesmo array. Isso significa que você pode ter números, strings, objetos e até outros arrays no mesmo array.
let misturado = [1, "dois", { nome: "três" }, [4, 5]];
- No exemplo acima, o array
misturado
contém um número (1
), uma string ("dois"
), um objeto ({ nome: "três" }
), e outro array ([4, 5]
), mostrando a flexibilidade do tipo de dados que pode ser armazenado.
-
push():
- Adiciona um ou mais elementos ao final do array e retorna o novo comprimento do array.
- Esse método modifica o array original.
frutas.push("uva"); console.log(frutas); // ["maçã", "banana", "laranja", "uva"]
- Explicação: Ao usar
push()
, o elemento"uva"
foi adicionado ao final do arrayfrutas
. O array agora contém 4 elementos.
-
pop():
- Remove o último elemento do array e retorna esse elemento removido.
- Este método também modifica o array original.
let ultimaFruta = frutas.pop(); console.log(ultimaFruta); // "uva" console.log(frutas); // ["maçã", "banana", "laranja"]
- Explicação: O método
pop()
remove"uva"
do final do array e o retorna. O arrayfrutas
agora tem apenas 3 elementos.
-
unshift():
- Adiciona um ou mais elementos no início do array, movendo os elementos existentes para posições superiores.
- Retorna o novo comprimento do array.
frutas.unshift("morango"); console.log(frutas); // ["morango", "maçã", "banana", "laranja"]
- Explicação: O método
unshift()
adiciona o elemento"morango"
ao início do arrayfrutas
, fazendo com que os outros elementos sejam deslocados para a direita.
-
shift():
- Remove o primeiro elemento do array e o retorna.
- Este método também altera o array original.
let primeiraFruta = frutas.shift(); console.log(primeiraFruta); // "morango" console.log(frutas); // ["maçã", "banana", "laranja"]
- Explicação: O método
shift()
remove o primeiro elemento do array, neste caso"morango"
, e retorna esse valor. O array restante é agora composto por"maçã"
,"banana"
, e"laranja"
.
-
indexOf():
- Retorna o índice do primeiro elemento encontrado no array que corresponda ao valor fornecido. Se o elemento não for encontrado, retorna
-1
.
console.log(frutas.indexOf("banana")); // 1
- Explicação: O método
indexOf()
encontra o índice do elemento"banana"
no array, que é 1, pois ele é o segundo elemento do array.
- Retorna o índice do primeiro elemento encontrado no array que corresponda ao valor fornecido. Se o elemento não for encontrado, retorna
-
slice():
- Retorna uma cópia rasa de uma porção de um array, sem modificar o array original. Os parâmetros indicam o índice de início e o índice final da parte do array a ser copiada.
let parte = frutas.slice(1, 3); console.log(parte); // ["banana", "laranja"]
- Explicação: O método
slice()
extrai os elementos do array entre os índices 1 e 3 (não incluindo o índice 3), retornando o novo array com os elementos"banana"
e"laranja"
.
-
splice():
- Modifica o conteúdo de um array removendo, substituindo ou adicionando elementos. Os parâmetros indicam o índice de início, o número de elementos a serem removidos, e os novos elementos a serem inseridos.
frutas.splice(1, 1, "kiwi", "manga"); console.log(frutas); // ["maçã", "kiwi", "manga", "laranja"]
- Explicação: O método
splice()
remove um elemento no índice 1, que é"banana"
, e insere os elementos"kiwi"
e"manga"
nesse local, alterando o array original.
-
includes():
- Verifica se um determinado elemento está presente no array. Retorna
true
se o elemento for encontrado efalse
caso contrário. Também pode receber um segundo argumento para indicar de qual índice a busca deve começar.
const frutas = ["maçã", "banana", "laranja"]; console.log(frutas.includes("banana")); // true console.log(frutas.includes("uva")); // false console.log(frutas.includes("maçã", 1)); // false (começa a buscar a partir do índice 1)
- Explicação: O método
includes()
verifica a presença do elemento. Se"banana"
está no array, retornatrue
. Se"uva"
não está presente, retornafalse
. A busca pode ser iniciada de um índice específico, como demonstrado ao procurar"maçã"
a partir do índice 1, resultando emfalse
pois o primeiro elemento é"banana"
.
- Verifica se um determinado elemento está presente no array. Retorna
-
forEach():
- O método
forEach()
executa uma função fornecida uma vez para cada elemento do array. Ele não retorna um novo array, apenas executa a função para cada item. - Exemplo:
frutas.forEach(function(fruta) { console.log(fruta); });
- Explicação: Neste exemplo, a função anônima é chamada para cada elemento do array
frutas
. Para cada iteração, o valor da fruta é impresso no console. A saída será:maçã banana laranja
- O método
-
map():
- O método
map()
cria um novo array com os resultados da chamada de uma função para cada elemento do array original. O array original não é alterado. - Exemplo:
let maiusculas = frutas.map(fruta => fruta.toUpperCase()); console.log(maiusculas); // ["MAÇÃ", "KIWI", "MANGA", "LARANJA"]
- Explicação: O
map()
aplica a funçãotoUpperCase()
a cada elemento defrutas
, criando um novo array com os nomes das frutas em maiúsculas. O array original não é modificado.
- O método
-
filter():
- O método
filter()
cria um novo array contendo todos os elementos do array original que atendem à condição especificada na função fornecida. - Exemplo:
let frutasComM = frutas.filter(fruta => fruta.startsWith('m')); console.log(frutasComM); // ["manga"]
- Explicação: O
filter()
cria um novo array contendo apenas os elementos que começam com a letra "m". Neste caso, o único item que atende a essa condição é"manga"
. O array original não é alterado.
- O método
-
reduce():
- O método
reduce()
aplica uma função acumuladora a cada elemento do array, resultando em um único valor de retorno. O primeiro argumento da função é o acumulador (que mantém o valor acumulado), e o segundo é o valor atual do array. Um valor inicial pode ser fornecido ao acumulador. - Exemplo:
let numeros = [1, 2, 3, 4, 5]; let soma = numeros.reduce((acumulador, atual) => acumulador + atual, 0); console.log(soma); // 15
- Explicação: O
reduce()
começa com o valor inicial de0
e soma cada elemento do array. O valor acumulado é atualizado a cada iteração, e o resultado final é a soma de todos os elementos, que é15
.
- O método
Arrays bidimensionais são arrays que contêm outros arrays como seus elementos, criando uma estrutura semelhante a uma matriz. Cada elemento do array principal pode ser considerado uma "linha", e os elementos dentro de cada linha podem ser considerados "colunas". Esse tipo de estrutura é frequentemente usado para representar tabelas ou grades.
let matriz = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
Explicação:
- Neste exemplo,
matriz
é um array contendo três arrays internos, cada um representando uma linha. O primeiro array interno contém os números 1, 2 e 3, o segundo contém 4, 5 e 6, e o terceiro contém 7, 8 e 9. Juntos, esses arrays formam uma matriz 3x3.
Para acessar elementos em um array bidimensional, usamos dois índices: o primeiro índice refere-se à linha, e o segundo índice refere-se à coluna.
console.log(matriz[1][2]); // 6
Explicação:
- O primeiro índice (
1
) refere-se à segunda linha da matriz (lembre-se que a indexação começa em 0), e o segundo índice (2
) refere-se ao terceiro elemento da linha. Portanto,matriz[1][2]
retorna o valor6
.
Podemos usar loops aninhados para iterar sobre arrays bidimensionais. O primeiro loop percorre as linhas, e o segundo loop percorre as colunas de cada linha.
for (let i = 0; i < matriz.length; i++) {
for (let j = 0; j < matriz[i].length; j++) {
console.log(matriz[i][j]);
}
}
Explicação:
- O primeiro
for
percorre cada linha da matriz, e o segundofor
percorre cada elemento dentro da linha. O valor de cada elemento é impresso no console. Neste caso, o código exibirá todos os números da matriz de 1 a 9.
- flat():
- O método flat() é usado para "achar" arrays aninhados, ou seja, transforma arrays de várias dimensões em um único array.
let arrayAchatado = matriz.flat();
console.log(arrayAchatado); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Explicação:
- O
flat()
pega os elementos de todos os arrays internos e os coloca em um único array. O resultado será um array unidimensional com todos os valores da matriz original.
- map() com arrays aninhados:
O método map()
pode ser usado para aplicar uma função a cada elemento, até mesmo em arrays aninhados. Ele cria um novo array, deixando o original inalterado.
let matrizDobrada = matriz.map(linha => linha.map(num => num * 2));
console.log(matrizDobrada);
// [[2, 4, 6], [8, 10, 12], [14, 16, 18]]
Explicação:
- O
map()
é aplicado duas vezes: uma vez para cada linha e outra para cada número dentro de uma linha. Como resultado, todos os números da matriz são multiplicados por 2.
Arrays bidimensionais são extremamente úteis para representar dados tabulares, como:
- Tabelas de banco de dados
- Grades de jogos
- Matrizes de imagem
Eles são amplamente usados em algoritmos de processamento de dados, manipulação de imagens, e jogos como o "campo minado" ou tabuleiros de xadrez.
Objetos em JavaScript são estruturas de dados que permitem armazenar coleções de pares chave-valor. Eles são fundamentais para a programação em JavaScript e são usados para representar entidades do mundo real ou conceitos abstratos. Cada chave (ou propriedade) é associada a um valor, que pode ser de qualquer tipo, incluindo outro objeto ou uma função.
Objetos são amplamente utilizados para modelar entidades mais complexas, como uma pessoa, um carro, ou até mesmo funcionalidades de um sistema. Eles permitem uma organização mais flexível e expressiva dos dados.
-
Usando a notação literal de objeto:
- Esta é a maneira mais comum e direta de criar um objeto. A notação literal de objeto usa chaves
{}
para definir as propriedades e valores de um objeto.
let pessoa = { nome: "João", idade: 30, profissao: "Desenvolvedor" }; console.log(pessoa.nome); // "João"
- Explicação: A chave
nome
tem o valor"João"
, a chaveidade
tem o valor30
, e a chaveprofissao
tem o valor"Desenvolvedor"
. Esses valores são armazenados dentro do objetopessoa
.
- Esta é a maneira mais comum e direta de criar um objeto. A notação literal de objeto usa chaves
-
Usando o construtor Object():
- O construtor
Object()
pode ser usado para criar um objeto vazio e adicionar propriedades a ele posteriormente. Isso é útil quando se deseja criar objetos dinamicamente.
let carro = new Object(); carro.marca = "Toyota"; carro.modelo = "Corolla"; carro.ano = 2022; console.log(carro.marca); // "Toyota"
- Explicação: Aqui, o objeto
carro
foi criado usando o construtornew Object()
. As propriedades foram adicionadas ao objeto posteriormente com a notação de ponto (carro.marca = "Toyota"
). O valor de cada chave é acessado através da notação de ponto ou colchetes.
- O construtor
Existem duas maneiras principais de acessar as propriedades de um objeto: usando a notação de ponto ou a notação de colchetes.
-
Notação de ponto:
- A notação de ponto é a maneira mais simples e direta de acessar uma propriedade de um objeto. Basta usar o nome do objeto seguido de um ponto e o nome da propriedade.
console.log(pessoa.nome); // "João"
- Explicação: Neste exemplo, a propriedade
nome
do objetopessoa
é acessada diretamente usando a notação de ponto. Isso retorna o valor associado à chavenome
, que é"João"
.
-
Notação de colchetes:
- A notação de colchetes é útil quando o nome da propriedade é dinâmico ou quando a chave contém caracteres especiais ou espaços. A propriedade é especificada dentro de colchetes e como uma string.
console.log(pessoa["idade"]); // 30
- Explicação: A notação de colchetes é usada para acessar a propriedade
idade
do objetopessoa
. Isso retorna o valor associado à chaveidade
, que é30
. A notação de colchetes também pode ser usada quando a chave é uma variável ou quando o nome da chave tem caracteres especiais.
let chave = "profissao"; console.log(pessoa[chave]); // "Desenvolvedor"
-
Adicionando ou Modificando Propriedades:
- Você pode adicionar novas propriedades a um objeto ou modificar o valor de uma propriedade existente usando a notação de ponto ou colchetes.
pessoa.idade = 31; // Modifica a propriedade idade pessoa.email = "joao@example.com"; // Adiciona uma nova propriedade console.log(pessoa.idade); // 31 console.log(pessoa.email); // "joao@example.com"
-
Deletando Propriedades:
- A palavra-chave
delete
pode ser usada para remover uma propriedade de um objeto.
delete pessoa.email; console.log(pessoa.email); // undefined
- A palavra-chave
Objetos também podem conter funções, chamadas de métodos. Esses métodos podem acessar e manipular as propriedades do objeto.
- Criando um método em um objeto:
let pessoa = { nome: "João", idade: 30, saudacao: function() { console.log("Olá, meu nome é " + this.nome); } }; pessoa.saudacao(); // "Olá, meu nome é João"
- Explicação: O objeto
pessoa
tem um método chamadosaudacao
, que acessa a propriedadenome
do próprio objeto usando a palavra-chavethis
. O método imprime uma saudação no console.
- Explicação: O objeto
Objetos podem conter outros objetos como propriedades, criando uma estrutura mais complexa. Isso permite representar dados hierárquicos ou mais detalhados.
let pessoa = {
nome: "João",
endereco: {
rua: "Rua A",
numero: 123
}
};
console.log(pessoa.endereco.rua); // "Rua A"
- Explicação: No exemplo acima, a propriedade
endereco
é um objeto que contém as propriedadesrua
enumero
. O acesso a essas propriedades é feito encadeando os acessos com a notação de ponto:pessoa.endereco.rua
.
Métodos são funções que pertencem a um objeto e podem ser usados para realizar operações ou manipular dados associados a esse objeto. Eles são definidos dentro do objeto como uma propriedade cujo valor é uma função. Em vez de apenas armazenar dados, os métodos permitem que os objetos realizem tarefas ou cálculos com esses dados.
Exemplo de um objeto com método:
let pessoa = {
nome: "Maria",
saudacao: function() {
console.log("Olá, eu sou " + this.nome);
}
};
pessoa.saudacao(); // "Olá, eu sou Maria"
Explicação: O objeto pessoa
tem uma propriedade chamada saudacao
, que é um método (uma função). Dentro da função, a palavra-chave this
faz referência ao objeto atual, ou seja, this.nome
acessa o valor da propriedade nome
do objeto pessoa
. Quando chamamos pessoa.saudacao()
, ele imprime "Olá, eu sou Maria" no console.
Em JavaScript, você pode adicionar ou remover propriedades e métodos dinamicamente de um objeto. Isso permite modificar objetos em tempo de execução, de acordo com a necessidade.
- Adicionando propriedades: Você pode adicionar uma nova propriedade a um objeto a qualquer momento.
pessoa.email = "maria@email.com";
console.log(pessoa.email); // "maria@email.com"
- Deletando propriedades: Para remover uma propriedade de um objeto, utilizamos a palavra-chave
delete
.
delete pessoa.idade;
console.log(pessoa.idade); // undefined
Explicação:
- No exemplo acima, adicionamos dinamicamente a propriedade
email
ao objetopessoa
e, em seguida, removemos a propriedadeidade
utilizando o operadordelete
.
Esses três métodos são bastante úteis quando você precisa iterar sobre as propriedades de um objeto ou quando precisa acessar suas chaves e valores de uma forma estruturada.
Object.keys()
: Este método retorna um array contendo todas as chaves (propriedades) de um objeto.
console.log(Object.keys(pessoa));
// ["nome", "saudacao", "email"]
Explicação:
- O método
Object.keys(pessoa)
retorna um array com os nomes de todas as propriedades do objetopessoa
. Neste caso, o resultado é["nome", "saudacao", "email"]
.
Object.values()
: Este método retorna um array contendo todos os valores das propriedades de um objeto.
console.log(Object.values(pessoa));
// ["Maria", [Function: saudacao], "maria@email.com"]
Explicação:
- O método
Object.values(pessoa)
retorna um array com os valores associados a cada chave do objetopessoa
. Neste caso, os valores são"Maria"
, a função do métodosaudacao
, e"maria@email.com"
.
Object.entries()
: Este método retorna um array de arrays, onde cada sub-array contém dois elementos: o nome da chave e seu valor.
console.log(Object.entries(pessoa));
// [["nome", "Maria"], ["saudacao", [Function: saudacao]], ["email", "maria@email.com"]]
Explicação:
- O método
Object.entries(pessoa)
retorna um array de pares chave-valor. Cada par é representado como um sub-array, onde o primeiro elemento é a chave e o segundo é o valor correspondente.
Esses métodos são úteis, por exemplo, quando você precisa iterar sobre as propriedades de um objeto, ou quando deseja transformar um objeto em um formato mais fácil de manipular, como arrays. A combinação desses métodos com loops, como forEach ou map, pode tornar o trabalho com objetos mais flexível e eficiente.
Funções são blocos de código reutilizáveis que realizam uma tarefa específica ou calculam um valor. Elas são essenciais para organizar, modularizar e tornar o código mais legível e reutilizável. Ao aprender como definir, chamar e manipular funções, você ganha flexibilidade no desenvolvimento de soluções em JavaScript.
As funções em JavaScript podem ser definidas de várias maneiras:
-
Declaração de função: A declaração de função é a forma tradicional de definir uma função. Quando você usa a palavra-chave
function
, está criando uma função nomeada, que pode ser chamada por seu nome em qualquer lugar do código após sua declaração. Caracteristicas:- São hoisted (elevadas), ou seja, você pode chamar a função antes de sua declaração no código.
- Não há limitações quanto ao número de parâmetros que a função pode ter.
function saudacao(nome) { console.log("Olá, " + nome + "!"); }
-
Expressão de função: Em uma expressão de função, você cria uma função anônima (sem nome) e a atribui a uma variável. Essas funções podem ser passadas como argumentos ou retornadas por outras funções. Caracteristicas:
- Não podem ser chamadas antes de sua definição no código.
- São comumente usadas em callbacks ou em funções que são passadas como argumentos.
let saudacao = function(nome) { console.log("Olá, " + nome + "!"); };
-
Arrow function (ES6+): As arrow functions são uma forma mais compacta e moderna de escrever funções, introduzida no ES6. Elas são especialmente úteis para funções curtas e quando você precisa de uma sintaxe mais concisa. Uma das principais vantagens das arrow functions é que elas mantêm o valor de
this
do contexto em que foram definidas, o que pode evitar certos problemas com o escopo. Caracteristicas:- Sintaxe mais curta: As arrow functions têm uma forma mais compacta, sem a necessidade da palavra-chave
function
. - Não possuem
this
próprio: Elas herdam o valor dethis
do contexto em que foram criadas, o que as torna mais seguras quando se trata de manipulação de this dentro de funções anônimas. - Imutabilidade do
this
: Isso é especialmente útil em situações como em callbacks dentro de objetos ou métodos.
- Sintaxe mais curta: As arrow functions têm uma forma mais compacta, sem a necessidade da palavra-chave
let saudacao = (nome) => {
console.log("Olá, " + nome + "!");
};
saudacao("Auyber"); // Olá, Auyber!
A sintaxe da arrow function elimina a palavra-chave function
e o uso das chaves ({}
) pode ser omitido quando a função tem apenas uma linha de código:
let saudacao = nome => console.log("Olá, " + nome + "!");
saudacao("Auyber"); // Olá, Auyber!
Por que this
é importante nas arrow functions?
- Uma das principais vantagens das arrow functions é que elas não têm seu próprio valor de
this
. Em vez disso, elas herdam o valor dethis
do contexto em que foram criadas. - Isso resolve o problema comum de que o valor de
this
pode ser alterado em funções anônimas dentro de objetos, especialmente quando você trabalha com métodos de objetos ou dentro de eventos. Exemplo comthis
:
const obj = {
nome: "Auyber",
saudacao: function() {
setTimeout(function() {
console.log("Olá, " + this.nome); // Aqui 'this' refere-se ao contexto global ou undefined em modo estrito.
}, 1000);
}
};
obj.saudacao(); // Olá, undefined
Usando a arrow function o problema de escopo é resolvido
const obj = {
nome: "Auyber",
saudacao: function() {
setTimeout(() => {
console.log("Olá, " + this.nome); // 'this' refere-se ao obj.
}, 1000);
}
};
obj.saudacao(); // Olá, Auyber
Nesse exemplo, a arrow function mantém o valor de this
do objeto obj
, enquanto a função tradicional de setTimeout
mudaria o valor de this
para o escopo global (ou undefined
no modo estrito).
Após a definição de uma função, você pode chamá-la em qualquer ponto do código. Para chamar a função, basta usar o nome dela seguido de parênteses, passando os parâmetros necessários.
saudacao("Alice"); // "Olá, Alice!"
Explicação:
- A função
saudaca
o é chamada com o argumento"Alice"
, que substitui o parâmetronome
na definição da função.
Parâmetros são variáveis que você define ao criar uma função. Elas representam valores que são passados para a função quando ela é chamada. Esses parâmetros são usados para personalizar o comportamento da função com base nos valores fornecidos.
Parâmetros Básicos
function soma(a, b) {
return a + b;
}
console.log(soma(5, 3)); // 8
Explicação:
- A função
soma
recebe dois parâmetrosa
eb
e retorna a soma deles. Ao chamá-la com os valores 5 e 3, ela retorna 8.
** Parâmetros Padrão (ES6+)**
Parâmetros padrão são valores que você pode fornecer para uma função no caso de o argumento não ser passado na chamada. Isso permite definir valores predefinidos sem precisar fazer verificações dentro da função.
function saudacao(nome = "Visitante") {
console.log("Olá, " + nome + "!");
}
saudacao(); // "Olá, Visitante!"
saudacao("Alice"); // "Olá, Alice!"
Explicação:
- A função
saudacao
tem o parâmetronome
com um valor padrão de"Visitante"
. Se nenhum valor for passado, ela usará esse valor. Caso contrário, usará o valor fornecido.
Rest Parameters (ES6+)
O operador rest (...) permite que uma função aceite um número indefinido de argumentos como um array. Isso é útil quando você não sabe quantos argumentos serão passados para a função.
function soma(...numeros) {
return numeros.reduce((total, num) => total + num, 0);
}
console.log(soma(1, 2, 3, 4)); // 10
Explicação:
- A função
soma
usa o operador rest para agrupar todos os argumentos passados em um array chamadonumeros
. O métodoreduce
é então usado para somar todos os valores desse array.
Desestruturação de Parâmetros (ES6+)
A desestruturação de parâmetros em JavaScript é uma funcionalidade introduzida no ES6 que permite "desempacotar" valores de objetos ou arrays diretamente como variáveis, tornando o código mais limpo e conciso.
Como funciona a Desestruturação em Parâmetros
Normalmente, ao passar um objeto como argumento para uma função, precisaríamos acessar suas propriedades manualmente. Com a desestruturação, podemos extrair diretamente as propriedades ou elementos que desejamos usar, dentro da assinatura da função.
Exemplo básico com um objeto
function imprimirPessoa({ nome, idade }) {
console.log(`${nome} tem ${idade} anos.`);
}
imprimirPessoa({ nome: "Carlos", idade: 25 }); // "Carlos tem 25 anos."
Explicação:
A função imprimirPessoa
aceita um objeto como parâmetro.
Na assinatura da função, usamos { nome, idade }
para desestruturar as propriedades nome
e idade
do objeto passado.
Isso elimina a necessidade de acessar manualmente objeto.nome ou objeto.idade
dentro da função.
Vantagens:
- Reduz a repetição de código.
- Torna o código mais legível e claro.
- Facilita o uso de objetos com muitas propriedades, já que podemos extrair apenas as que nos interessam.
- Funciona muito bem com objetos complexos ou dados retornados de APIs.
ANTES DE PROSSEGUIR COM MAIS EXEMPLOS, VAMOS FALAR SOBRE:
Uso de $
e de crases (Template Literals)
Em JavaScript, template literals (ou literais de template) são uma funcionalidade introduzida no ES6 que permite criar strings mais dinâmicas e legíveis. Eles utilizam crases (
) em vez de aspas ('
ou "
), e permitem a inserção de expressões dentro da string com o uso do ${}
.
Template Literals com ${}
O ${}
é usado para interpolar expressões dentro de strings. Isso significa que você pode incluir variáveis ou qualquer expressão válida de JavaScript diretamente na string, sem precisar concatenar.
Exemplo básico:
const nome = "Carlos";
const idade = 25;
console.log(`${nome} tem ${idade} anos.`);
// Saída: "Carlos tem 25 anos."
Explicação:
As crases definem uma template string.
O ${}
permite que expressões JavaScript sejam avaliadas e substituídas pelo valor resultante.
No exemplo, ${nome}
será substituído pelo valor da variável nome
, e ${idade}
pelo valor de idade
.
VOLTANDO A FALAR SOBRE DESTRUTURAÇÃO:
Exemplo avançado com valores padrão Se a propriedade esperada não for fornecida, você pode definir valores padrão durante a desestruturação:
function imprimirPessoa({ nome = "Desconhecido", idade = 0 }) {
console.log(`${nome} tem ${idade} anos.`);
}
imprimirPessoa({ nome: "Ana" }); // "Ana tem 0 anos."
imprimirPessoa({}); // "Desconhecido tem 0 anos."
Explicação:
Quando nome
ou idade
não são fornecidos, os valores padrão nome = "Desconhecido"
e idade = 0
são utilizados.
Desestruturação com Arrays A desestruturação também funciona com arrays, permitindo acessar seus elementos diretamente:
function imprimirNumeros([primeiro, segundo, terceiro]) {
console.log(`Os números são: ${primeiro}, ${segundo}, e ${terceiro}.`);
}
imprimirNumeros([1, 2, 3]); // "Os números são: 1, 2, e 3."
Explicação:
A função imprimirNumeros
recebe um array como argumento.
Na assinatura da função, [primeiro, segundo, terceiro]
extrai os valores dos primeiros três elementos do array.
Desestruturação com Objetos e Arrays Aninhados A desestruturação também suporta estruturas aninhadas, permitindo acessar dados em profundidade:
Exemplo com Objetos Aninhados
function imprimirEndereco({ endereco: { cidade, estado } }) {
console.log(`Cidade: ${cidade}, Estado: ${estado}`);
}
imprimirEndereco({
endereco: { cidade: "São Paulo", estado: "SP" },
});
// "Cidade: São Paulo, Estado: SP"
Exemplo com Arrays Aninhados
function imprimirMatriz([[a, b], [c, d]]) {
console.log(`Os valores são: ${a}, ${b}, ${c}, e ${d}.`);
}
imprimirMatriz([
[1, 2],
[3, 4],
]);
// "Os valores são: 1, 2, 3, e 4."
Combinação de Objetos e Arrays Você pode combinar objetos e arrays para acessar estruturas complexas:
function imprimirDados({ nome, notas: [primeira, segunda] }) {
console.log(`${nome} tirou ${primeira} na primeira prova e ${segunda} na segunda.`);
}
imprimirDados({
nome: "João",
notas: [8, 9],
});
// "João tirou 8 na primeira prova e 9 na segunda."
O retorno de uma função é o valor que ela fornece quando é chamada. O return
é usado para indicar o valor que a função devolve, permitindo que esse valor seja usado fora da função.
Retorno Básico
function quadrado(numero) {
return numero * numero;
}
console.log(quadrado(4)); // 16
Explicação:
- A função
quadrado
recebe um número e retorna o valor desse número elevado ao quadrado. No exemplo,4
é passado e a função retorna16
.
Retorno Implícito em Arrow Functions
Arrow functions podem retornar um valor diretamente sem usar a palavra-chave return
se o corpo da função for uma única expressão.
const cubo = x => x * x * x;
console.log(cubo(3)); // 27
Explicação:
- A função
cubo
retorna diretamente o valor de x elevado ao cubo, sem a necessidade de usar a palavra-chavereturn
.
Retornando Múltiplos Valores
Em JavaScript, você pode retornar múltiplos valores usando um objeto ou um array. Isso é útil quando você precisa retornar informações relacionadas em um único valor.
function calcularArea(largura, altura) {
let area = largura * altura;
let perimetro = 2 * (largura + altura);
return { area, perimetro };
}
let resultado = calcularArea(5, 3);
console.log(resultado.area); // 15
console.log(resultado.perimetro); // 16
Explicação:
- A função
calcularArea
retorna um objeto contendo a área e o perímetro de um retângulo. Os valores podem ser acessados pelo nome das propriedadesarea
eperimetro
.
Retorno Antecipado
Às vezes, você pode querer sair de uma função antes que ela termine sua execução. Isso pode ser feito com o comando return
. Isso é útil para evitar execuções desnecessárias ou retornar rapidamente em caso de erro.
function verificarIdade(idade) {
if (idade < 0) {
return "Idade inválida";
}
if (idade >= 18) {
return "Maior de idade";
}
return "Menor de idade";
}
console.log(verificarIdade(20)); // "Maior de idade"
console.log(verificarIdade(-5)); // "Idade inválida"
Explicação:
- A função
verificarIdade
verifica a idade e retorna imediatamente quando a idade for inválida ou se a pessoa for maior de idade, sem precisar passar pelas outras verificações.
Funções são um conceito fundamental em JavaScript. Elas permitem organizar e reutilizar código, tornando-o modular e mais fácil de entender. A compreensão dos diferentes tipos de funções, como funções tradicionais, expressões de funções, arrow functions e os conceitos de parâmetros e retornos, é essencial para escrever código eficiente e bem estruturado. Ao trabalhar com funções, você cria blocos de código independentes que podem ser chamados sempre que necessário, tornando a programação mais poderosa e flexível.
Escopo em JavaScript refere-se à visibilidade e acessibilidade de variáveis, funções e objetos em diferentes partes do código. Compreender o escopo é crucial para evitar bugs e escrever código mais eficiente.
-
Escopo Global
- Variáveis declaradas fora de qualquer função ou bloco têm escopo global.
- Podem ser acessadas de qualquer lugar no código.
- Quando uma variável é declarada no escopo global, ela pode ser acessada por qualquer função ou bloco dentro do mesmo contexto.
var globalVar = "Eu sou global"; function teste() { console.log(globalVar); // Acessível } teste(); // "Eu sou global"
-
Escopo de Função
- Variáveis declaradas dentro de uma função só são acessíveis dentro dessa função.
- O escopo de função cria um "ambiente isolado", o que significa que variáveis definidas dentro de uma função não são acessíveis fora dela.
function minhaFuncao() { var funcaoVar = "Eu sou local à função"; console.log(funcaoVar); // Acessível } minhaFuncao(); // "Eu sou local à função" console.log(funcaoVar); // Erro: funcaoVar is not defined
-
Escopo de Bloco (introduzido com let e const no ES6)
- Variáveis declaradas com let e const têm escopo de bloco.
- Um bloco é definido por chaves
{}
e pode ser um loop, uma estrutura condicional, ou qualquer outro conjunto de instruções delimitado por chaves. - As variáveis declaradas com
let
ouconst
não são acessíveis fora do bloco onde foram declaradas, o que ajuda a evitar o vazamento de variáveis para fora de estruturas de controle, evitando possíveis erros.
if (true) { let blocoVar = "Eu sou local ao bloco"; console.log(blocoVar); // Acessível } console.log(blocoVar); // Erro: blocoVar is not defined
-
A cadeia de escopos é a maneira como JavaScript procura variáveis. Quando uma variável é acessada, o JavaScript começa a busca no escopo mais interno e vai subindo para os escopos mais externos até encontrar a variável ou até chegar ao escopo global.
-
A cadeia de escopos é essencial para entender o comportamento das variáveis em funções aninhadas.
var externa = "Eu sou externa"; function externa() { var interna = "Eu sou interna"; function interna() { console.log(externa); // Acessível console.log(interna); // Acessível } interna(); } externa();
-
No exemplo acima, a variável
externa
é acessada dentro da função interna, porque ela pertence ao escopo mais externo, e a funçãointerna
pode acessar a variável do escopo que a contém.
-
Hoisting (ou içamento) é um comportamento do JavaScript onde declarações de variáveis e funções são movidas para o topo de seu escopo durante a execução do código.
-
Isso significa que você pode usar variáveis e funções antes de elas serem declaradas, mas somente para funções e variáveis declaradas com
var
(não comlet
ouconst
).console.log(x); // undefined (não dá erro) var x = 5;
Como o código é interpretado:
var x; console.log(x); // undefined x = 5;
-
No exemplo acima, a declaração
var x;
é "elevada" ao topo do código, mas a inicializaçãox = 5;
ocorre no ponto em que ela aparece no código. Por isso, o valor dex
éundefined
quando acessado antes da inicialização. -
Hoisting de Funções:
- O hoisting também se aplica a funções. Funções declaradas com a palavra-chave
function
são totalmente "içadas", ou seja, podem ser chamadas antes de sua declaração no código.
minhaFuncao(); // "Função hoisted" function minhaFuncao() { console.log("Função hoisted"); }
- O hoisting também se aplica a funções. Funções declaradas com a palavra-chave
-
Hoisting de
let
econst
:let
econst
não são "içadas" da mesma forma quevar
. Elas entram em uma "zona morta" (temporal dead zone, ou TDZ) no topo do escopo, o que significa que você não pode acessá-las antes da linha de declaração.
console.log(a); // Erro: Cannot access 'a' before initialization let a = 5;
Compreender como o escopo funciona em JavaScript é essencial para evitar erros comuns e garantir que o código seja claro e eficiente. A compreensão dos tipos de escopo, como a cadeia de escopos e o hoisting, permitirá que você escreva código mais robusto e organizado.
Métodos são funções que são propriedades de um objeto. Eles definem o comportamento do objeto, permitindo que o objeto realize ações ou retorne valores. Em JavaScript, os métodos são usados para manipular e interagir com os dados dentro de objetos.
-
Na declaração do objeto:
- Um método pode ser definido diretamente dentro de um objeto usando a palavra-chave
function
seguida da definição da função.
let pessoa = { nome: "Alice", saudacao: function() { console.log("Olá, eu sou " + this.nome); } }; pessoa.saudacao(); // "Olá, eu sou Alice"
- Neste exemplo, o método
saudacao
pertence ao objetopessoa
. Quandopessoa.saudacao()
é chamado, a função imprime o valor da propriedadenome
do objetopessoa
.
- Um método pode ser definido diretamente dentro de um objeto usando a palavra-chave
-
Usando a sintaxe de método abreviada (ES6+):
- A partir do ES6, é possível usar uma sintaxe mais curta para definir métodos em objetos. Não é necessário usar a palavra-chave
function
; basta definir o nome do método e a função diretamente.
let pessoa = { nome: "Bob", saudacao() { console.log("Olá, eu sou " + this.nome); } };
- A sintaxe abreviada torna o código mais conciso e legível.
- A partir do ES6, é possível usar uma sintaxe mais curta para definir métodos em objetos. Não é necessário usar a palavra-chave
-
Adicionando métodos a um objeto existente:
- É possível adicionar novos métodos a um objeto depois de sua criação. Isso é útil quando você deseja estender as funcionalidades de um objeto dinamicamente.
pessoa.despedida = function() { console.log("Tchau!"); };
- Neste exemplo, o método
despedida
é adicionado ao objetopessoa
depois que ele já foi definido. Agora, podemos chamarpessoa.despedida()
para imprimir "Tchau!".
A palavra-chave this
refere-se ao objeto que está chamando o método. O this
é uma maneira de acessar as propriedades e outros métodos do objeto dentro do próprio método.
-
Em um método,
this
é o próprio objeto que contém a função. No exemplo abaixo,this
dentro do métododescricao
se refere ao objetocarro
.let carro = { marca: "Toyota", modelo: "Corolla", descricao() { console.log(`Este carro é um ${this.marca} ${this.modelo}`); } }; carro.descricao(); // "Este carro é um Toyota Corolla"
- Quando chamamos
carro.descricao()
, o método imprime a marca e o modelo do carro, usandothis.marca
ethis.modelo
para acessar as propriedades do objetocarro
.
- Quando chamamos
Métodos também podem ser definidos dentro de objetos aninhados, e o comportamento de this
se aplica de forma semelhante.
let empresa = {
nome: "Tech Solutions",
endereco: {
rua: "Rua Principal",
numero: 123,
mostrarEndereco() {
console.log(`A empresa está localizada na ${this.rua}, ${this.numero}`);
}
}
};
empresa.endereco.mostrarEndereco(); // "A empresa está localizada na Rua Principal, 123"
- No exemplo acima,
this.rua
ethis.numero
referem-se ao objetoendereco
dentro do objetoempresa
.
Além de executar ações, métodos também podem retornar valores. Isso é útil quando você precisa manipular ou calcular dados dentro de um objeto e fornecer esses valores para outras partes do seu código.
let contaBancaria = {
saldo: 1000,
deposito(valor) {
this.saldo += valor;
console.log(`Depósito de R$${valor} realizado.`);
},
consultarSaldo() {
return `O saldo atual é R$${this.saldo}`;
}
};
contaBancaria.deposito(500); // "Depósito de R$500 realizado."
console.log(contaBancaria.consultarSaldo()); // "O saldo atual é R$1500"
- O método
deposito
altera o valor desaldo
, e o métodoconsultarSaldo
retorna o saldo atualizado.
Métodos também podem ser usados em arrays, permitindo que você modifique ou acesse os elementos do array de maneira eficiente.
let numeros = [1, 2, 3, 4, 5];
let soma = numeros.reduce(function(acumulado, atual) {
return acumulado + atual;
}, 0);
console.log(soma); // 15
- O método
reduce()
é um exemplo de método de array que executa uma função em cada elemento do array, acumulando um valor final. Neste caso, ele soma todos os números do array.
Funções recursivas são funções que chamam a si mesmas para resolver problemas. Elas são úteis em casos onde um problema pode ser dividido em subproblemas menores e mais simples, que são semelhantes ao problema original. A recursão pode simplificar o código, tornando-o mais conciso e fácil de entender.
Uma função recursiva é estruturada da seguinte forma:
function funcaoRecursiva(parametro) {
if (condicaoDeParada) {
return valorFinal;
}
return funcaoRecursiva(novoParametro);
}
- Condição de parada: A condição de parada é crucial para evitar que a função continue chamando a si mesma indefinidamente, resultando em um loop infinito. Essa condição garante que a função pare de se chamar quando o problema for resolvido.
- Chamada recursiva: Caso a condição de parada não seja satisfeita, a função chama a si mesma com um novo parâmetro, aproximando-se da solução.
Um exemplo clássico de recursão é o cálculo do fatorial de um número.
function fatorial(n) {
if (n === 0 || n === 1) {
return 1;
}
return n * fatorial(n - 1);
}
console.log(fatorial(5)); // 120
- Neste exemplo, a função
fatorial
calcula o fatorial de um númeron
. A condição de parada é quandon
é igual a 0 ou 1, pois o fatorial de 0 ou 1 é 1. Caso contrário, a função chama a si mesma comn - 1
até que a condição de parada seja atingida.
-
Defina uma condição de parada clara: A condição de parada é fundamental para que a recursão tenha um ponto de término. Sem ela, a função continuará chamando a si mesma infinitamente, causando um erro de stack overflow (estouro da pilha de chamadas). Sempre certifique-se de que, em algum momento, a função atenderá à condição de parada.
-
Recursão vs. Iteração: A recursão pode ser mais elegante e compacta para problemas simples, mas pode ser menos eficiente para grandes volumes de dados, já que a pilha de chamadas pode crescer rapidamente. Soluções iterativas (com loops) podem ser mais eficientes em termos de uso de memória para esses casos.
-
Risco de Estouro de Pilha: Quando uma função recursiva faz muitas chamadas, ela empilha as funções na memória. Se as chamadas forem muito profundas, pode ocorrer um stack overflow, onde a pilha de chamadas excede a capacidade de memória. Para evitar isso, é importante usar recursão com cautela, especialmente em problemas com uma grande quantidade de iterações.
Exemplo de Estouro de Pilha:
function recursaoProfunda(n) {
if (n <= 0) {
return;
}
recursaoProfunda(n - 1); // A função chamando a si mesma muitas vezes
}
recursaoProfunda(100000); // Pode resultar em "Maximum call stack size exceeded"
- Memoização e Recursão: Para melhorar a performance de funções recursivas, especialmente em problemas com subproblemas que se repetem (como na sequência de Fibonacci), é possível usar memoização. Isso envolve armazenar os resultados de chamadas recursivas anteriores para evitar recomputações.
Exemplo de Fibonacci com Memoização:
let memo = {};
function fibonacci(n) {
if (n === 0) return 0;
if (n === 1) return 1;
if (memo[n]) return memo[n]; // Retorna o valor armazenado se já calculado
memo[n] = fibonacci(n - 1) + fibonacci(n - 2); // Armazena o resultado
return memo[n];
}
console.log(fibonacci(10)); // 55
- A memoização ajuda a evitar que a função refaça o mesmo cálculo repetidamente, tornando o processo mais eficiente.
- Fibonacci: A sequência de Fibonacci é um exemplo clássico de problema recursivo, onde cada número é a soma dos dois números anteriores. A versão recursiva simples não é eficiente, mas a memoização melhora muito a performance.
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
- Busca Binária: A busca binária em um array ordenado pode ser implementada recursivamente. A cada chamada recursiva, a busca é reduzida pela metade até encontrar o valor ou determinar que ele não existe.
function buscaBinaria(arr, alvo, inicio = 0, fim = arr.length - 1) {
if (inicio > fim) return -1; // Condição de parada: não encontrado
let meio = Math.floor((inicio + fim) / 2);
if (arr[meio] === alvo) {
return meio;
} else if (arr[meio] < alvo) {
return buscaBinaria(arr, alvo, meio + 1, fim);
} else {
return buscaBinaria(arr, alvo, inicio, meio - 1);
}
}
- Percorrendo Estruturas de Dados Hierárquicas: Estruturas de dados como árvores e gráficos podem ser percorridas de maneira recursiva. Por exemplo, uma árvore binária pode ser percorrida em profundidade (DFS) com recursão.
function percorrerArvore(no) {
if (no === null) return;
console.log(no.valor);
percorrerArvore(no.esquerda);
percorrerArvore(no.direita);
}
Funções recursivas são uma ferramenta poderosa em programação, especialmente para resolver problemas que podem ser divididos em subproblemas menores. Porém, é importante garantir uma condição de parada, considerar a eficiência de soluções recursivas versus iterativas e estar ciente dos riscos de estouro de pilha. Com o uso adequado, a recursão pode simplificar a resolução de muitos problemas complexos.
Funções anônimas são funções sem nome. Elas são frequentemente usadas como argumentos para outras funções, atribuídas a variáveis ou utilizadas em expressões de maneira temporária. A principal vantagem das funções anônimas é sua flexibilidade, permitindo que sejam usadas diretamente no lugar onde são necessárias, sem a necessidade de uma declaração formal.
Uma função anônima pode ser atribuída a uma variável ou passada como argumento diretamente. Aqui está um exemplo simples de como isso funciona:
let saudacao = function(nome) {
console.log("Olá, " + nome);
};
saudacao("Carlos"); // "Olá, Carlos"
- Neste exemplo, a função não tem nome e é atribuída à variável
saudacao
. Em seguida, a função é chamada passando um argumento.
As funções anônimas são frequentemente usadas como callbacks. Um callback é uma função passada como argumento para outra função, que a invoca em algum ponto de sua execução. Veja um exemplo utilizando a função setTimeout
para aguardar dois segundos antes de executar o código:
setTimeout(function() {
console.log("Isso será impresso após 2 segundos");
}, 2000);
- Aqui, a função anônima é executada após o atraso de 2000 milissegundos (2 segundos).
Com o ECMAScript 6 (ES6), surgiram as arrow functions, que são uma forma mais concisa e expressiva de escrever funções anônimas. Além disso, as arrow functions mantêm o contexto do this
, o que pode ser útil em algumas situações.
Sintaxe
let dobrar = (x) => x * 2;
console.log(dobrar(4)); // 8
- Neste exemplo, a função
dobrar
é uma arrow function que recebe um parâmetrox
e retornax * 2
. É importante notar que, ao utilizar arrow functions, a sintaxe fica mais compacta, e a palavra-chavefunction
não é necessária.
Sintaxe com mais de um parâmetro
Quando há mais de um parâmetro, os parênteses são necessários:
let soma = (a, b) => a + b;
console.log(soma(2, 3)); // 5
Sintaxe sem parâmetros
Se a função não receber parâmetros, pode-se usar parênteses vazios:
let saudacao = () => console.log("Olá, mundo!");
saudacao(); // "Olá, mundo!"
Uma IIFE é uma função anônima que é definida e executada imediatamente. Ela é frequentemente usada para criar um escopo local, evitando que as variáveis internas vazem para o escopo global.
(function() {
let privada = "Não posso ser acessada fora";
console.log(privada);
})();
- Nesse caso, a função é definida e invocada na mesma linha, criando um escopo temporário para a variável
privada
, que não pode ser acessada fora da função.
As funções anônimas são particularmente úteis em diversas situações, como:
- Encapsulamento: Ao usar funções anônimas dentro de outras funções, podemos criar variáveis temporárias ou locais que não afetem o escopo global.
- Callbacks: Como vimos no exemplo com setTimeout, as funções anônimas são comumente usadas para passar funções como parâmetros para outras funções.
- Modularização: Em aplicações mais complexas, funções anônimas podem ser usadas para dividir lógicas de execução, mantendo o código mais organizado e modular.
Em resumo, funções anônimas oferecem uma maneira flexível de trabalhar com funções temporárias, encapsulando dados e comportamentos sem a necessidade de criar nomes ou declarações explícitas para cada uma delas.
High-order functions (HOFs) são funções que podem receber outras funções como argumentos e/ou retornar funções como resultados. Elas são fundamentais em JavaScript e permitem criar código mais flexível e dinâmico.
- Funções de primeira classe: Em JavaScript, funções podem ser passadas como argumentos para outras funções, ou podem ser retornadas de outras funções.
- Modularidade e reutilização: Ao tratar funções como objetos de primeira classe, HOFs permitem criar código mais modular e reutilizável.
- Uso em programação funcional: HOFs são amplamente utilizadas em programação funcional, onde se favorece a aplicação de funções em vez de manipulação de estado ou dados mutáveis.
- Funções que recebem callbacks:
function executarFuncao(funcao) {
funcao();
}
executarFuncao(() => {
console.log('Função passada como argumento!');
});
- Neste exemplo, a função
executarFuncao
recebe uma função como argumento (um callback) e a executa dentro do seu corpo. O callback é uma função anônima que apenas imprime uma mensagem no console.
- Funções que retornam funções:
function criarMultiplicador(multiplicador) {
return function(numero) {
return numero * multiplicador;
};
}
const dobrar = criarMultiplicador(2);
console.log(dobrar(5)); // 10
- Aqui,
criarMultiplicador
é uma função que retorna outra função. Essa função interna recebe um número e o multiplica pelo valor demultiplicador
, que foi definido quando a função foi criada. O exemplo cria um "dobrador" e usa para multiplicar 5 por 2.
JavaScript oferece várias HOFs nativas para trabalhar com arrays, tornando a manipulação de dados mais eficiente e legível:
forEach()
: Executa uma função para cada elemento do array
[1, 2, 3].forEach(num => console.log(num));
forEach()
percorre todos os elementos de um array e executa a função fornecida em cada um deles. Embora não retorne nada, é útil para operações como efeitos colaterais (ex: imprimir algo no console).
map()
: Cria um novo array com os resultados da função aplicada a cada elemento
const dobrados = [1, 2, 3].map(num => num * 2);
console.log(dobrados); // [2, 4, 6]
map()
transforma cada elemento do array aplicando uma função a ele e retorna um novo array com os resultados. A função fornecida deve retornar um valor para cada item, gerando assim um novo array.
filter()
: Cria um novo array com todos os elementos que passam no teste da função
const pares = [1, 2, 3, 4].filter(num => num % 2 === 0);
console.log(pares); // [2, 4]
filter()
cria um novo array com os elementos que atendem a uma condição específica definida pela função fornecida. Neste exemplo, ele retorna os números pares do array original.
reduce()
: Reduz o array a um único valor, aplicando uma função acumuladora
const soma = [1, 2, 3].reduce((acc, num) => acc + num, 0);
console.log(soma); // 6
reduce()
aplica uma função acumuladora a cada item do array, retornando um único valor. No exemplo, ele soma todos os números do array.
some()
: Verifica se pelo menos um elemento satisfaz a condição
const temPar = [1, 2, 3].some(num => num % 2 === 0);
console.log(temPar); // true
some()
verifica se ao menos um elemento do array atende à condição fornecida. Neste caso, ele retornatrue
porque o número 2 é par.
every()
: Verifica se todos os elementos satisfazem a condição
const todosPares = [2, 4, 6].every(num => num % 2 === 0);
console.log(todosPares); // true
every()
verifica se todos os elementos do array atendem à condição fornecida. Neste caso, ele retornatrue
porque todos os números no array são pares.
As High-order Functions são poderosas e fazem parte do núcleo da programação em JavaScript, ajudando a criar código mais eficiente, modular e reutilizável. Com o uso de funções como map()
, filter()
, reduce()
, entre outras, é possível realizar uma vasta gama de manipulações de dados de maneira mais declarativa e legível.
O objeto global em JavaScript é um objeto especial que serve como contêiner para variáveis e funções globalmente acessíveis. Ele é fundamental para o ambiente de execução JavaScript e possui algumas características importantes:
- Criação automática: O objeto global é criado automaticamente pelo ambiente JavaScript quando o código é executado.
- Propriedades e métodos nativos: Ele contém diversas propriedades e métodos que são usados frequentemente, como
parseInt()
,Math
,JSON
, entre outros. - Varia conforme o ambiente de execução: O objeto global pode variar dependendo de onde o código JavaScript está sendo executado.
- Navegador: No ambiente de navegador, o objeto global é o
window
. Ele é responsável por fornecer acesso a várias funcionalidades da página web, como manipulação do DOM, eventos e propriedades da janela. - Node.js: Em ambientes Node.js, o objeto global é o
global
, que serve como contêiner para variáveis e funções acessíveis de qualquer parte do código. - Contexto estrito (strict mode): Em "strict mode" (modo estrito), o objeto global é
undefined
, o que significa que não é possível acessar variáveis globais diretamente sem explicitamente referenciá-las.
Propriedades:
undefined
: Um valor especial que representa a ausência de valor ou a falta de definição de uma variável.NaN
: "Not a Number", é um valor que representa um erro numérico.Infinity
: Representa um valor infinito, positivo ou negativo, dependendo do contexto.
Funções:
parseInt()
: Converte uma string para um número inteiro.
parseInt("10"); // 10
parseFloat()
: Converte uma string para um número de ponto flutuante.
parseFloat("10.5"); // 10.5
isNaN()
: Verifica se o valor não é um número.
isNaN("texto"); // true
Construtores:
Object()
: Usado para criar um novo objeto.
const obj = new Object();
Array()
: Usado para criar um novo array.
const arr = new Array(5); // Cria um array com 5 elementos indefinidos
Function()
: Construtor que cria novas funções.
const func = new Function('a', 'b', 'return a + b');
Objetos:
Math
: Um objeto que fornece métodos e propriedades para realizar operações matemáticas, comoMath.max()
,Math.random()
,Math.PI
, etc.
Math.max(10, 20); // 20
Math.random(); // Valor aleatório entre 0 e 1
JSON
: Um objeto que fornece métodos para trabalhar com JSON, comoJSON.stringify()
eJSON.parse()
.
const obj = { name: "John" };
const jsonString = JSON.stringify(obj); // Converte o objeto em string JSON
Embora o objeto global seja útil, o uso excessivo de variáveis globais pode causar problemas no código, como:
- Conflitos de nome: Se muitas variáveis ou funções globais são usadas, elas podem ter o mesmo nome, resultando em substituição de valores inesperada.
- Manutenção difícil: O código que depende fortemente do escopo global pode ser difícil de manter e entender, pois as variáveis podem ser modificadas de qualquer lugar.
- Escopo poluído: Ao criar variáveis globais, há o risco de "poluir" o escopo global, o que torna o gerenciamento de variáveis mais complexo.
- Evitar variáveis globais: Sempre que possível, use escopos locais para variáveis e funções. Utilize módulos ou closures para manter o código organizado e seguro.
- Usar módulos: Com a introdução de módulos ES6 (import e export), é possível limitar o escopo de variáveis e funções ao módulo, reduzindo a dependência do objeto global.
- Em ambientes como Node.js: Use o objeto global com moderação, preferindo a utilização de módulos
require
para evitar conflitos.
Eventos em JavaScript permitem que ações específicas sejam executadas dentro de uma página HTML de forma dinâmica, sem travar o carregamento da página. São interações do usuário ou do sistema que disparam a execução de código JavaScript. (ex: clique, scroll, envio de formulário).
Como Funcionam?
- Código Inline (Evitar!):
<!-- Não recomendado: mistura HTML com JS --> <button onclick="alert('Cliquei!')">Clique aqui</button>
Método Recomendado (addEventListener):
const button = document.querySelector('button');
button.addEventListener('click', function() {
alert('Cliquei!');
});
Melhor Prática para Inclusão de Código JavaScript
O correto é incluir o código JavaScript em um arquivo separado (.js
) e referenciá-lo dentro do HTML usando a tag <script src="script.js"></script>
.
O DOM é uma representação da estrutura do HTML na forma de uma árvore de objetos. Através do JavaScript, podemos acessar e manipular esses elementos.
Exemplo de Hierarquia do DOM:
HTML > BODY > H1, P, TABLE > TR (tabela possui linhas <tr>)
Outro exemplo: Estrutura do DOM
<!-- Exemplo: -->
<html>
<body>
<h1>Título</h1>
<div id="container">
<p class="texto">Parágrafo</p>
</div>
</body>
</html>
Árvore DOM do exemplo acima:
document └── html └── body ├── h1 └── div#container └── p.texto
Para acessar o DOM no console do navegador:
document // Retorna a estrutura da página
Selecionar múltiplos elementos:
document.getElementsByTagName("tag")
→ Retorna umaHTMLCollection
.document.getElementsByClassName("classe")
→ Retorna umaHTMLCollection
.document.getElementsByName("nome")
→ Retorna umaNodeList
.document.querySelectorAll("seletor")
→ Retorna umaNodeList
.
Selecionar um único elemento:
document.getElementById("id")
document.querySelector("seletor")
Adicionando Novos Elementos ao DOM
- Criamos o elemento.
- Manipulamos ele.
- Adicionamos a um nó existente na página.
Exemplo:
const novoElemento = document.createElement("p");
novoElemento.innerText = "Este é um novo parágrafo.";
document.body.appendChild(novoElemento);
Passo a Passo:
Criar Elemento:
const novoElemento = document.createElement('div');
Manipular o Elemento:
novoElemento.textContent = 'Novo conteúdo';
novoElemento.classList.add('destaque');
Adicionar ao DOM:
document.body.append(novoElemento); // Adiciona no final do body
Métodos de Inserção
Método | Descrição |
---|---|
append() |
Adiciona vários elementos/texto |
appendChild() |
Adiciona um único elemento |
prepend() |
Insere no início do elemento pai |
Atenção: O uso de innerHTML
pode abrir brechas de segurança ao permitir injeção de scripts maliciosos. É preferível usar textContent
ou createElement()
.
⚠️ **Perigo do innerHTML:**
Permite injetar HTML dinâmico, mas é vulnerável a XSS (Cross-Site Scripting):
// Exemplo perigoso:
elemento.innerHTML = '<img src=x onerror="alert(\'Hackeado!\')">';
// Alternativa segura:
elemento.textContent = 'Texto seguro';
Podemos adicionar eventos diretamente no HTML:
<button onclick="minhaFuncao()">Clique Aqui</button>
Ou utilizar addEventListener()
no JavaScript:
const button = document.querySelector("button");
button.addEventListener("click", minhaFuncao);
Exemplo de envio de valores do DOM para o JavaScript:
<h2>Registre-se!</h2>
<section>
<label for="username">Nome de Usuário:</label>
<input type="text" id="username">
<br>
<label for="password">Senha:</label>
<input type="password" id="password">
<br>
<button onclick="register(this.parentNode)">Registrar</button>
</section>
function register(element) {
const username = element.children.username.value;
const password = element.children.password.value;
alert("Usuário " + username + " registrado!");
}
button.removeEventListener("click", minhaFuncao);
No submit
de um formulário, usamos:
event.preventDefault();
Isso evita que o navegador recarregue a página ao enviar o formulário.
Manipulação de Formulários Exemplo de Validação:
<form id="formRegistro">
<input type="text" id="username">
<input type="password" id="password">
<button type="submit">Registrar</button>
</form>
document.getElementById('formRegistro').addEventListener('submit', function(ev) {
ev.preventDefault(); // Impede o recarregamento
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
if (password.length < 6) {
alert('Senha deve ter pelo menos 6 caracteres!');
return;
}
// Enviar dados para o servidor...
});
Podemos alterar estilos diretamente pelo JavaScript via Propriedade style
:
document.body.style.color = "#212529";
Outro exemplo:
const titulo = document.querySelector('h1');
titulo.style.color = '#ff0000'; // CamelCase (não usa hífens)
titulo.style.fontSize = '24px';
Importante:
- No CSS, as propriedades são escritas em
kebab-case
(background-color
). - No JS, usamos
camelCase
(backgroundColor
).
O método toggle()
é usado para adicionar ou remover uma classe de um elemento HTML de forma dinâmica. Se a classe já estiver presente, ela será removida; se não estiver, será adicionada.
Uso principal: Alternar classes no DOM
O toggle()
é geralmente aplicado no classList
de um elemento para criar efeitos visuais como ativar/desativar um tema escuro ou mostrar/ocultar um menu.
Sintaxe:
element.classList.toggle("classe");
Exemplos de uso
1. Alternando Tema Claro/Escuro
const button = document.getElementById("theme-toggle");
button.addEventListener("click", function () {
document.body.classList.toggle("dark-mode");
});
.dark-mode {
background-color: #333;
color: white;
}
O que acontece?
- Se
dark-mode
já estiver no<body>
, ele será removido. - Se não estiver, ele será adicionado.
2. Criando um Menu Expansível
const menu = document.getElementById("menu");
const toggleButton = document.getElementById("menu-button");
toggleButton.addEventListener("click", () => {
menu.classList.toggle("show");
});
.show {
display: block;
}
Funcionamento:
- Cada clique no botão alterna a visibilidade do menu.
O toggle()
pode receber um segundo argumento booleano (true
para adicionar a classe, false
para removê-la):
element.classList.toggle("classe", true); // Garante que a classe será adicionada
element.classList.toggle("classe", false); // Garante que a classe será removida
Para obter e definir valores de atributos:
const input = document.getElementById("input");
console.log(input.value); // Pega o valor atual
console.log(input.getAttribute("value")); // Pega o valor inicial do HTML
input.setAttribute("value", "Novo valor"); // Altera o valor do atributo
Podemos armazenar valores personalizados nos elementos usando data-*
:
<div data-user-id="123">Usuário</div>
const userId = document.querySelector("div").dataset.userId;
console.log(userId); // 123
Outro exemplo:
<div data-id="123" data-usuario-role="admin"></div>
const div = document.querySelector('div');
console.log(div.dataset.id); // "123"
console.log(div.dataset.usuarioRole); // "admin" (kebab-case vira camelCase)
focus()
O método focus()
é usado para definir o foco em um elemento da página, geralmente um campo de entrada (<input>
, <textarea>
). Isso é útil para melhorar a experiência do usuário, como ao carregar uma página de login ou um formulário.
Exemplo: Focar automaticamente em um campo de entrada
document.getElementById("username").focus();
- Quando a página carregar, o cursor será posicionado automaticamente no campo de entrada com
id="username"
.
Uso comum do focus()
- Destacar automaticamente o primeiro campo de um formulário.
- Auxiliar na acessibilidade, garantindo que usuários de teclado ou leitores de tela naveguem corretamente.
- Melhorar a usabilidade em modais, onde o primeiro campo recebe foco automaticamente ao abrir.
eval()
O método eval()
permite executar código JavaScript armazenado dentro de uma string. No entanto, seu uso deve ser evitado sempre que possível, pois pode representar um risco de segurança ao permitir a execução de código arbitrário.
Exemplo: Executando expressões matemáticas com eval()
console.log(eval("2 + 2")); // 4
Exemplo: Executando código dinâmico (não recomendado!)
let x = 5;
let y = 10;
console.log(eval("x * y")); // 50
Por que eval()
é perigoso?
Se um usuário mal-intencionado conseguir inserir código arbitrário que será executado com eval()
, isso pode levar a ataques como injeção de código.
Exemplo de um risco de segurança
let userInput = "alert('Hackeado!')";
eval(userInput); // Executa um alerta no navegador
- Se
userInput
for controlado por um usuário externo, ele pode injetar comandos perigosos.
Alternativa segura ao eval()
Se precisar interpretar operações matemáticas de strings, prefira o Function ou JSON.parse()
em alguns casos:
const safeEval = new Function("return " + "2 + 2");
console.log(safeEval()); // 4
Ou, para cálculos simples:
const expression = "2 + 2";
console.log(Function(`"use strict"; return (${expression})`)()); // 4
- Use
focus()
para melhorar a usabilidade e acessibilidade de formulários. - Evite
eval()
, pois ele pode representar um risco à segurança da aplicação. Prefira alternativas mais seguras para interpretar e executar código dinâmico.
Existem três principais formas de armazenamento no navegador:
- Session Storage - Armazena dados temporariamente (enquanto a aba está aberta).
- Local Storage - Armazena dados permanentemente (mesmo após fechar o navegador).
- Cookies - Permitem armazenar informações tanto no navegador quanto no servidor.
Exemplo de uso do Local Storage:
localStorage.setItem("chave", "valor");
console.log(localStorage.getItem("chave"));
Posicionamento do Script:
Use defer para carregar scripts após o DOM:
<script src="script.js" defer></script>
Ou coloque scripts antes do fechamento do :
<body>
<!-- Conteúdo -->
<script src="script.js"></script>
</body>
Depuração no Console: Inspecione elementos:
console.dir(document.getElementById('elemento')); // Mostra propriedades detalhadas