JavaScript - Características
Recursos Principais
O JavaScript possui vários recursos principais que o tornam uma linguagem de programação poderosa e flexível para desenvolvimento web. Esses recursos incluem variáveis e tipos de dados, operadores, fluxo de controle e funções.
Variáveis e Tipos de Dados
No JavaScript, você pode declarar variáveis usando as palavras-chave var
, let
ou const
. var
é a forma tradicional de declarar variáveis, enquanto let
e const
foram introduzidas no ES6 (ECMAScript 2015) para fornecer escopo de bloco e imutabilidade.
O JavaScript possui vários tipos de dados primitivos:
Tipo de Dado | Descrição |
---|---|
number |
Representa valores numéricos, tanto inteiros quanto números de ponto flutuante |
string |
Representa dados textuais, entre aspas simples ou duplas |
boolean |
Representa um valor lógico, true ou false |
null |
Representa um valor nulo deliberado |
undefined |
Representa uma variável que foi declarada, mas não recebeu um valor |
O JavaScript também possui um tipo de dado object
, que pode conter coleções de pares chave-valor ou estruturas mais complexas.
JavaScript é uma linguagem de tipagem dinâmica, o que significa que as variáveis podem conter valores de qualquer tipo de dado, e o tipo de uma variável pode mudar durante a execução. Essa flexibilidade é alcançada por meio de coerção e conversão de tipos, onde o JavaScript converte automaticamente valores de um tipo para outro quando necessário.
Operadores
O JavaScript fornece uma variedade de operadores para realizar operações em valores:
- Operadores aritméticos:
+
,-
,*
,/
,%
,++
,--
- Operadores de atribuição:
=
,+=
,-=
,*=
,/=
,%=
- Operadores de comparação:
==
,===
,!=
,!==
,>
,<
,>=
,<=
- Operadores lógicos:
&&
,||
,!
- Operador ternário:
condição ? valor1 : valor2
Fluxo de Controle
O JavaScript oferece várias declarações de fluxo de controle que permitem controlar a execução do código com base em certas condições ou repetir blocos de código várias vezes.
- Declarações
if...else
: Executam um bloco de código se uma condição especificada for verdadeira, ou outro bloco de código se a condição for falsa - Declaração
switch
: Avalia uma expressão e executa o bloco de código correspondente com base no caso correspondente - Loop
for
: Repete um bloco de código por um número especificado de vezes - Loops
while
edo...while
: Repetem um bloco de código enquanto uma condição especificada for verdadeira - Declarações
break
econtinue
: Alteram o fluxo dos loops, terminando o loop ou pulando para a próxima iteração
Funções
Funções são blocos de código reutilizáveis que executam tarefas específicas. No JavaScript, você pode definir funções usando a palavra-chave function
seguida pelo nome da função e um conjunto de parênteses contendo parâmetros opcionais.
Exemplo: Declaração de Função
function saudacao(nome) {
console.log("Olá, " + nome + "!");
}
Funções podem aceitar parâmetros como entrada e retornar valores usando a palavra-chave return
. Elas podem ser chamadas pelo seu nome seguido de parênteses contendo quaisquer argumentos necessários.
O JavaScript também suporta expressões de função, onde as funções podem ser atribuídas a variáveis ou passadas como argumentos para outras funções.
Exemplo: Expressão de Função
const quadrado = function(x) {
return x * x;
};
As funções de seta, introduzidas no ES6, fornecem uma sintaxe concisa para definir funções, particularmente quando usadas como callbacks ou em padrões de programação funcional.
Exemplo: Função de Seta
const multiplicar = (a, b) => a * b;
Esses recursos principais formam a base do JavaScript e são essenciais para escrever programas básicos a complexos no desenvolvimento web. Entender e dominar esses recursos permitirá que você crie aplicações web dinâmicas e interativas.
Recursos Avançados
JavaScript possui muitos recursos avançados que permitem escrever código mais complexo e eficiente. Esses recursos incluem objetos e arrays, classes e herança, programação assíncrona e tratamento de erros.
Objetos e Arrays
Objetos e arrays são estruturas de dados importantes em JavaScript. Objetos armazenam coleções de pares chave-valor, enquanto arrays armazenam listas ordenadas de valores.
Para criar um objeto, você pode usar a notação literal de objeto ou o construtor Object
. Você pode acessar e modificar propriedades do objeto usando a notação de ponto ou a notação de colchetes.
Exemplo: Criando e acessando propriedades de objetos
const pessoa = {
nome: "João",
idade: 30,
cidade: "São Paulo"
};
console.log(pessoa.nome); // Saída: "João"
pessoa.idade = 31;
console.log(pessoa["cidade"]); // Saída: "São Paulo"
Arrays são criados usando a notação literal de array ou o construtor Array
. Você pode acessar e modificar elementos do array usando seus índices.
Exemplo: Criando e acessando elementos de arrays
const frutas = ["maçã", "banana", "laranja"];
console.log(frutas[0]); // Saída: "maçã"
frutas[1] = "uva";
console.log(frutas); // Saída: ["maçã", "uva", "laranja"]
Objetos e arrays possuem métodos integrados que permitem realizar operações comuns, como adicionar ou remover elementos, buscar valores e modificar dados.
JavaScript também suporta desestruturação, que permite extrair valores de objetos e arrays e atribuí-los a variáveis de forma concisa.
Exemplo: Desestruturação de objetos e arrays
const { nome, idade } = pessoa;
console.log(nome); // Saída: "João"
const [primeiro, segundo] = frutas;
console.log(segundo); // Saída: "uva"
Classes e Herança
JavaScript suporta programação orientada a objetos por meio de classes e herança. Classes são modelos para criar objetos com propriedades e métodos específicos.
Para definir uma classe, você usa a palavra-chave class
seguida pelo nome da classe. Dentro da classe, você pode definir um método construtor para inicializar as propriedades do objeto e outros métodos para definir o comportamento do objeto.
Exemplo: Definindo uma classe
class Retangulo {
constructor(largura, altura) {
this.largura = largura;
this.altura = altura;
}
calcularArea() {
return this.largura * this.altura;
}
}
Você pode criar instâncias de uma classe usando a palavra-chave new
seguida pelo nome da classe e quaisquer argumentos necessários.
Exemplo: Criando uma instância de classe
const ret = new Retangulo(5, 3);
console.log(ret.calcularArea()); // Saída: 15
JavaScript também suporta herança, permitindo criar novas classes baseadas em classes existentes. Você pode usar a palavra-chave extends
para criar uma subclasse que herda propriedades e métodos de uma superclasse.
Exemplo: Herança em JavaScript
class Quadrado extends Retangulo {
constructor(lado) {
super(lado, lado);
}
}
const quadrado = new Quadrado(4);
console.log(quadrado.calcularArea()); // Saída: 16
Subclasses podem sobrescrever métodos da superclasse usando o mesmo nome de método. Elas também podem chamar o método da superclasse usando a palavra-chave super
.
Programação Assíncrona
JavaScript é uma linguagem de thread único, o que significa que o código é executado sequencialmente. No entanto, JavaScript fornece maneiras de lidar com operações assíncronas, como fazer requisições HTTP ou ler arquivos, sem bloquear a execução de outro código.
No passado, a programação assíncrona em JavaScript era feita usando callbacks. Um callback é uma função passada como argumento para outra função e é executada quando a operação assíncrona é concluída.
Exemplo: Programação assíncrona com callbacks
function buscarDados(callback) {
// Simulando uma operação assíncrona
setTimeout(() => {
const dados = "Olá, mundo!";
callback(dados);
}, 1000);
}
buscarDados((dados) => {
console.log(dados); // Saída: "Olá, mundo!"
});
No entanto, callbacks podem levar a código aninhado e complexo, conhecido como "callback hell". Para resolver esse problema, JavaScript introduziu Promises, que fornecem uma maneira melhor de lidar com operações assíncronas.
Promises representam a eventual conclusão ou falha de uma operação assíncrona e permitem encadear múltiplas operações assíncronas usando os métodos .then()
e .catch()
.
Exemplo: Programação assíncrona com Promises
function buscarDados() {
return new Promise((resolve, reject) => {
// Simulando uma operação assíncrona
setTimeout(() => {
const dados = "Olá, mundo!";
resolve(dados);
}, 1000);
});
}
buscarDados()
.then((dados) => {
console.log(dados); // Saída: "Olá, mundo!"
})
.catch((erro) => {
console.error(erro);
});
O ES2017 introduziu as palavras-chave async
e await
, que fornecem uma sintaxe que parece mais com código síncrono para trabalhar com Promises. Dentro de uma função async
, você pode usar a palavra-chave await
para pausar a execução até que uma Promise seja resolvida.
Exemplo: Programação assíncrona com async/await
async function buscarDados() {
// Simulando uma operação assíncrona
const dados = await new Promise((resolve) => {
setTimeout(() => {
resolve("Olá, mundo!");
}, 1000);
});
return dados;
}
buscarDados().then((dados) => {
console.log(dados); // Saída: "Olá, mundo!"
});
O loop de eventos e a pilha de chamadas do JavaScript trabalham juntos para gerenciar a execução de código síncrono e assíncrono. O loop de eventos verifica continuamente a pilha de chamadas e a fila de tarefas, executando tarefas da fila de tarefas quando a pilha de chamadas está vazia.
Tratamento de Erros
O tratamento de erros é uma parte importante da escrita de código JavaScript robusto. JavaScript fornece a declaração try...catch
para lidar com exceções que podem ocorrer durante a execução do código.
Você pode envolver o código que pode lançar um erro dentro de um bloco try
, e especificar o código para lidar com o erro no bloco catch
.
Exemplo: Tratamento de erros com try...catch
try {
// Código que pode lançar um erro
throw new Error("Algo deu errado!");
} catch (erro) {
console.error(erro.message); // Saída: "Algo deu errado!"
}
Você pode usar a palavra-chave throw
para lançar seus próprios erros ou objetos de erro personalizados. Isso permite lidar com tipos específicos de erros de maneira diferente.
Exemplo: Lançando erros personalizados
function dividir(a, b) {
if (b === 0) {
throw new Error("Divisão por zero!");
}
return a / b;
}
try {
console.log(dividir(10, 0));
} catch (erro) {
console.error(erro.message); // Saída: "Divisão por zero!"
}
Recursos do ES6+
O JavaScript evoluiu ao longo dos anos, e o ECMAScript 2015 (ES6) introduziu novos recursos que se tornaram amplamente adotados no desenvolvimento moderno de JavaScript. Esses recursos visam tornar a linguagem mais expressiva, concisa e fácil de trabalhar. Aqui estão alguns dos recursos notáveis do ES6+.
Template Literals
Template literals, também conhecidos como template strings, oferecem uma maneira de criar e manipular strings em JavaScript. Eles apresentam duas vantagens principais sobre a concatenação tradicional de strings:
- Strings Multi-linha: Os template literals permitem criar strings multi-linha sem a necessidade de caracteres de escape ou concatenação. Você pode envolver o conteúdo da sua string em crases (
Exemplo: String Multi-linha
const stringMultiLinha = `
Isto é uma
string multi-linha
usando template literals.
`;
- Interpolação de String: Os template literals suportam interpolação de string, o que permite incorporar expressões ou variáveis diretamente dentro da string. Ao envolver a expressão ou variável em
${}
, você pode incorporar valores dinâmicos em suas strings.
Exemplo: Interpolação de String
const nome = "João";
const idade = 30;
const mensagem = `Meu nome é ${nome} e eu tenho ${idade} anos.`;
console.log(mensagem); // Saída: "Meu nome é João e eu tenho 30 anos."
Atribuição por Desestruturação
A atribuição por desestruturação é uma forma de extrair valores de objetos ou arrays e atribuí-los a variáveis. Ela fornece uma sintaxe concisa para desempacotar valores de estruturas de dados.
- Desestruturação de Objeto: A desestruturação de objeto permite extrair propriedades específicas de um objeto e atribuí-las a variáveis com um nome correspondente.
Exemplo: Desestruturação de Objeto
const pessoa = {
nome: "João",
idade: 30,
cidade: "São Paulo"
};
const { nome, idade } = pessoa;
console.log(nome); // Saída: "João"
console.log(idade); // Saída: 30
- Desestruturação de Array: A desestruturação de array permite extrair valores de um array com base em sua posição e atribuí-los a variáveis.
Exemplo: Desestruturação de Array
const numeros = [1, 2, 3, 4, 5];
const [a, b, ...resto] = numeros;
console.log(a); // Saída: 1
console.log(b); // Saída: 2
console.log(resto); // Saída: [3, 4, 5]
A atribuição por desestruturação também suporta valores padrão, que são usados quando o valor extraído é indefinido, e permite renomear variáveis durante o processo de atribuição.
Arrow Functions
As arrow functions fornecem uma sintaxe concisa para definir funções em JavaScript. Elas oferecem uma alternativa compacta às expressões de função tradicionais.
- Sintaxe Concisa: As arrow functions eliminam a necessidade da palavra-chave
function
e usam a sintaxe=>
para definir a função.
Exemplo: Arrow Function - Sintaxe Concisa
const saudacao = (nome) => {
return `Olá, ${nome}!`;
};
console.log(saudacao("João")); // Saída: "Olá, João!"
Se o corpo da função consistir em uma única expressão, você pode omitir as chaves e a palavra-chave return
, tornando a sintaxe ainda mais concisa.
Exemplo: Arrow Function - Expressão Única
const quadrado = (x) => x * x;
console.log(quadrado(5)); // Saída: 25
- Vinculação Léxica do
this
: As arrow functions têm uma vinculação léxica dothis
, o que significa que elas herdam o valor dothis
do escopo circundante. Esse comportamento é útil ao trabalhar com métodos de objetos ou funções de callback.
Exemplo: Arrow Function - Vinculação Léxica do 'this'
const pessoa = {
nome: "João",
saudacao: function() {
setTimeout(() => {
console.log(`Olá, ${this.nome}!`);
}, 1000);
}
};
pessoa.saudacao(); // Saída: "Olá, João!" (após 1 segundo)
Módulos
O ES6 introduziu um sistema de módulos padronizado para JavaScript, permitindo organizar seu código em módulos reutilizáveis e encapsulados. Os módulos fornecem uma maneira de definir e compartilhar código em diferentes arquivos ou projetos.
- Exportando Módulos: Para tornar um valor, função ou classe disponível para uso em outros módulos, você precisa exportá-lo usando a palavra-chave
export
.
Exemplo: Exportando Módulos
// matematica.js
export function soma(a, b) {
return a + b;
}
export const PI = 3.14159;
- Importando Módulos: Para usar valores, funções ou classes de outro módulo, você precisa importá-los usando a palavra-chave
import
.
Exemplo: Importando Módulos
// principal.js
import { soma, PI } from './matematica.js';
console.log(soma(2, 3)); // Saída: 5
console.log(PI); // Saída: 3.14159
Os módulos também suportam exportações padrão, que permitem exportar um único valor como a exportação padrão de um módulo, e exportações nomeadas, que permitem exportar vários valores nomeados de um módulo.
Operadores Rest e Spread
Os operadores rest e spread (...
) fornecem uma maneira de trabalhar com vários elementos de forma concisa.
- Parâmetros Rest: O operador rest permite capturar vários argumentos passados para uma função como um array.
Exemplo: Parâmetros Rest
function soma(...numeros) {
return numeros.reduce((acc, curr) => acc + curr, 0);
}
console.log(soma(1, 2, 3, 4, 5)); // Saída: 15
- Operador Spread: O operador spread permite espalhar os elementos de um array ou objeto em outro array ou objeto.
Exemplo: Operador Spread
const numeros = [1, 2, 3];
const novosNumeros = [...numeros, 4, 5];
console.log(novosNumeros); // Saída: [1, 2, 3, 4, 5]
const pessoa = { nome: "João", idade: 30 };
const novaPessoa = { ...pessoa, cidade: "São Paulo" };
console.log(novaPessoa); // Saída: { nome: "João", idade: 30, cidade: "São Paulo" }
Estes são alguns dos recursos notáveis do ES6+ que foram introduzidos no JavaScript. Outros recursos incluem parâmetros padrão de função, literais de objeto aprimorados, classes, promessas e mais. Esses recursos melhoraram muito a expressividade, legibilidade e funcionalidade da linguagem, tornando o desenvolvimento JavaScript mais agradável e eficiente.