Estruturas de Dados Essenciais: Arrays
O gerenciamento eficiente de coleções é um pilar fundamental no desenvolvimento JavaScript. Abaixo, exploramos as diversas formas de instanciar e manipular arrays.
Métodos de Criação
// Sintaxe literal (preferencial)
const listaMercadorias = ['Notebook', 'Monitor', 'Teclado'];
// Construtor Array
const bufferVazio = new Array(10); // Espaço reservado para 10 itens
const coresPrimarias = new Array('Vermelho', 'Verde', 'Azul');
// Métodos Estáticos Modernos (ES6+)
const numerosUnicos = Array.of(42); // [42]
const sequencia = Array.from({ length: 3 }, (_, i) => i + 1); // [1, 2, 3]
// Conversão de Strings e Iteráveis
const letras = Array.from('JS'); // ['J', 'S']
Operações de Mutação e Cosnulta
Manipular o início, o fim ou posições específicas de um array exige conhecimento sobre quais métodos alteram a estrutura original.
const estoque = ['Cadeira', 'Mesa'];
// Modificações nas extremidades
estoque.push('Armário'); // Adiciona ao fim
estoque.pop(); // Remove do fim
estoque.unshift('Banco'); // Adiciona ao início
estoque.shift(); // Remove do início
// Splice: Versatilidade em qualquer posição
// (índice, quantidade_remover, ...itens_adicionar)
estoque.splice(1, 0, 'Lâmpada'); // Insere no índice 1 sem remover nada
// Localização de Elementos
const notas = [10, 8, 5, 8, 9];
const primeiraNotaOito = notas.indexOf(8); // 1
const possuiNotaBaixa = notas.includes(5); // true
const notaAlta = notas.find(n => n > 9); // 10
Processamento de Dados com Métodos Funcionais
A programação funcional em JavaScript permite transformar dados de forma declarativa e legível.
const produtos = [
{ id: 101, nome: 'Café', preco: 15, categoria: 'Alimento' },
{ id: 102, nome: 'Chá', preco: 10, categoria: 'Alimento' },
{ id: 103, nome: 'Caneca', preco: 25, categoria: 'Utensílio' }
];
// Transformação com Map
const nomesProdutos = produtos.map(p => p.nome.toUpperCase());
// Filtragem com Filter
const itensBaratos = produtos.filter(p => p.preco < 20);
// Agregação com Reduce
const valorTotalEstoque = produtos.reduce((acc, p) => acc + p.preco, 0);
// Validação com Every e Some
const todosSaoAlimentos = produtos.every(p => p.categoria === 'Alimento'); // false
const existeUtensilio = produtos.some(p => p.categoria === 'Utensílio'); // true
Explorando Objetos em Profundidade
Objetos em JavaScript são coleções dinâmicas de propriedades. Entender como controlar o acesso e a visibilidade dessas propriedades é crucial para a arquiteutra de sistemas.
Descritores de Porpriedade e Controle de Acesso
const configuracaoSessao = {
token: 'abc-123'
};
// Definindo propriedades com restrições
Object.defineProperty(configuracaoSessao, 'idUsuario', {
value: 5050,
writable: false, // Não pode ser alterado
enumerable: true, // Aparece em loops
configurable: false // Não pode ser deletado
});
// Getters e Setters dinâmicos
const contaBancaria = {
_saldo: 1000,
get saldoFormatado() {
return `R$ ${this._saldo.toFixed(2)}`;
},
set deposito(valor) {
if (valor > 0) this._saldo += valor;
}
};
Iteração e Transformação de Objetos
const metricas = { cpu: 45, memoria: 80, disco: 30 };
// Extração de chaves e valores
const chaves = Object.keys(metricas); // ['cpu', 'memoria', 'disco']
const valores = Object.values(metricas); // [45, 80, 30]
// Entradas para processamento em pares
Object.entries(metricas).forEach(([recurso, uso]) => {
console.log(`${recurso} está em ${uso}%`);
});
Estratégias de Clonagem: Raso vs Profundo
A gestão da mutabilidade exige atenção à forma como os objetos são copiados na memória.
Clonagem Rasa (Shallow Copy)
const perfilOriginal = { nome: 'Dev', stack: { principal: 'Node.js' } };
const copiaRasa = { ...perfilOriginal };
copiaRasa.stack.principal = 'React';
// Atenção: O perfilOriginal também foi alterado porque a referência do objeto interno é a mesma.
Clonagem Profunda (Deep Copy)
// Solução Moderna: StructuredClone API
const copiaProfunda = structuredClone(perfilOriginal);
// Implementação Recursiva Manual (Para ambientes legados)
function clonarObjeto(alvo, cache = new WeakMap()) {
if (alvo === null || typeof alvo !== 'object') return alvo;
if (cache.has(alvo)) return cache.get(alvo);
if (alvo instanceof Date) return new Date(alvo.getTime());
if (alvo instanceof RegExp) return new RegExp(alvo);
const clone = Array.isArray(alvo) ? [] : Object.create(Object.getPrototypeOf(alvo));
cache.set(alvo, clone);
for (const chave of Reflect.ownKeys(alvo)) {
clone[chave] = clonarObjeto(alvo[chave], cache);
}
return clone;
}
Desestruturação e Operador Spread
Estas funcionalidades simplificam a extração de dados e a composição de novas estruturas.
const configuracoes = { tema: 'dark', fonte: 'Fira Code', responsivo: true };
// Desestruturação com valores padrão e renomeação
const { tema, fonte: tipoLetra, linguagem = 'PT-BR' } = configuracoes;
// Spread para mesclagem de configurações
const configuracoesUsuario = { ...configuracoes, tema: 'light', mostrarLinhas: false };
// Desestruturação de Arrays
const coordenadas = [40.7128, -74.0060];
const [latitude, longitude] = coordenadas;
// Rest operator para capturar o restante
const [primeiro, ...resto] = [10, 20, 30, 40];
Aplicações Práticas
Utilitário de Agrupamento de Dados
const agruparPor = (colecao, atributo) => {
return colecao.reduce((agrupado, item) => {
const chave = item[atributo];
if (!agrupado[chave]) agrupado[chave] = [];
agrupado[chave].push(item);
return agrupado;
}, {});
};
const tarefas = [
{ titulo: 'A', status: 'pendente' },
{ titulo: 'B', status: 'concluido' },
{ titulo: 'C', status: 'pendente' }
];
console.log(agruparPor(tarefas, 'status'));
Acesso Seguro a Propriedades Aninhadas
function obterValor(obj, caminho, fallback) {
const chaves = caminho.split('.');
let resultado = obj;
for (const k of chaves) {
resultado = resultado?.[k];
if (resultado === undefined) return fallback;
}
return resultado;
}
const db = { users: { admin: { id: 1 } } };
console.log(obterValor(db, 'users.admin.id', 0)); // 1
console.log(obterValor(db, 'settings.theme', 'default')); // 'default'