Arrays: criando, acessando e iterando
1. Fundamentos da Criação de Arrays
Literais vs. Construtor new Array()
A forma mais comum e recomendada de criar arrays em JavaScript é usando literais:
// Literal (recomendado)
const frutas = ['maçã', 'banana', 'laranja'];
const numeros = [1, 2, 3, 4, 5];
const misto = [1, 'texto', true, { nome: 'João' }];
O construtor new Array() deve ser usado com cautela:
// Construtor - comportamentos inesperados
const arr1 = new Array(5); // Cria array esparso com 5 slots vazios
const arr2 = new Array(5, 10); // Cria [5, 10]
const arr3 = new Array('5'); // Cria ['5']
// Literal equivalente
const arr1Literal = [5]; // Cria [5]
Array.from() e Array.of() – Casos de Uso Modernos
Array.from() é excelente para converter objetos iteráveis ou array-like em arrays reais:
// Convertendo NodeList (DOM) em array
const elementos = document.querySelectorAll('div');
const arrayElementos = Array.from(elementos);
// Usando função de mapeamento
const quadrados = Array.from([1, 2, 3, 4], x => x * x);
// Resultado: [1, 4, 9, 16]
// Criando sequência numérica
const sequencia = Array.from({ length: 5 }, (_, i) => i + 1);
// Resultado: [1, 2, 3, 4, 5]
Array.of() resolve a ambiguidade do construtor:
const arr = Array.of(5); // [5] - sempre cria array com elementos
const arr2 = Array.of(5, 10, 15); // [5, 10, 15]
Arrays Esparsos e Array(length) – Armadilhas Comuns
Arrays esparsos têm "buracos" que podem causar comportamentos inesperados:
const esparso = [1, , 3]; // [1, empty, 3]
console.log(esparso[1]); // undefined
console.log(esparso.length); // 3
// Armadilhas com métodos de iteração
esparso.forEach(item => console.log(item)); // Só imprime 1 e 3 (pula o buraco)
const mapeado = esparso.map(x => x * 2); // [2, empty, 6]
2. Acessando Elementos e Propriedades Essenciais
Índices Numéricos e Notação de Colchetes
const cores = ['vermelho', 'azul', 'verde'];
console.log(cores[0]); // 'vermelho'
console.log(cores[2]); // 'verde'
// Índices negativos não funcionam com colchetes
console.log(cores[-1]); // undefined
Propriedade length – Comportamento Dinâmico e Mutação
const arr = [1, 2, 3];
console.log(arr.length); // 3
// Reduzir length remove elementos
arr.length = 2;
console.log(arr); // [1, 2]
// Aumentar length cria espaços vazios
arr.length = 5;
console.log(arr); // [1, 2, empty × 3]
Acessando o Último Elemento com at() (ES2022)
const numeros = [10, 20, 30, 40, 50];
// Método tradicional (menos legível)
console.log(numeros[numeros.length - 1]); // 50
// Método moderno com at()
console.log(numeros.at(-1)); // 50
console.log(numeros.at(-2)); // 40
console.log(numeros.at(0)); // 10
3. Iteração Clássica: Loops Tradicionais
for Clássico e for...in
const frutas = ['maçã', 'banana', 'laranja'];
// for clássico - controle total
for (let i = 0; i < frutas.length; i++) {
console.log(frutas[i]);
}
// for...in - NÃO recomendado para arrays (itera sobre propriedades)
for (let indice in frutas) {
console.log(frutas[indice]); // Funciona, mas pode incluir propriedades herdadas
}
while e do...while para Controle de Fluxo
const dados = [1, 2, 3, 4, 5];
let i = 0;
// while - útil quando não sabemos o número exato de iterações
while (i < dados.length) {
console.log(dados[i]);
i++;
}
// do...while - executa pelo menos uma vez
let j = 0;
do {
console.log(dados[j]);
j++;
} while (j < dados.length);
Otimização de Desempenho com Cache de length
// Sem cache - acessa length a cada iteração
for (let i = 0; i < arrayGrande.length; i++) {
// processamento
}
// Com cache - melhor performance
const len = arrayGrande.length;
for (let i = 0; i < len; i++) {
// processamento
}
4. Iteração Moderna: Métodos de Array Nativos
forEach() – Iteração Funcional e Limitações
const numeros = [1, 2, 3, 4, 5];
numeros.forEach((valor, indice, array) => {
console.log(`Índice ${indice}: ${valor}`);
});
// Limitação: não podemos usar break ou continue
// Para interromper, precisamos usar exceções (não recomendado)
for...of com entries(), keys() e values()
const cores = ['vermelho', 'azul', 'verde'];
// values() - padrão do for...of
for (const cor of cores) {
console.log(cor);
}
// keys() - obtém os índices
for (const indice of cores.keys()) {
console.log(indice);
}
// entries() - obtém pares [índice, valor]
for (const [indice, cor] of cores.entries()) {
console.log(`${indice}: ${cor}`);
}
Iteradores e o Protocolo Symbol.iterator
const arr = [10, 20, 30];
const iterador = arr[Symbol.iterator]();
console.log(iterador.next()); // { value: 10, done: false }
console.log(iterador.next()); // { value: 20, done: false }
console.log(iterador.next()); // { value: 30, done: false }
console.log(iterador.next()); // { value: undefined, done: true }
// Criando um iterador personalizado
function criarIterador(array) {
let indice = 0;
return {
next: () => {
if (indice < array.length) {
return { value: array[indice++], done: false };
}
return { done: true };
}
};
}
5. Arrays no Node.js: Manipulação e Performance
Buffer vs. Array – Diferenças e Conversões
const { Buffer } = require('buffer');
// Buffer é mais eficiente para dados binários
const buffer = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
console.log(buffer.toString()); // 'Hello'
// Convertendo Buffer para Array
const arrayFromBuffer = Array.from(buffer);
console.log(arrayFromBuffer); // [72, 101, 108, 108, 111]
// Array para Buffer
const arrayNumeros = [72, 101, 108, 108, 111];
const bufferFromArray = Buffer.from(arrayNumeros);
Streams e Arrays Grandes – Processamento Sob Demanda
const readline = require('readline');
const fs = require('fs');
// Processando arquivo linha por linha (evita carregar tudo na memória)
async function processarArquivoGrande(caminho) {
const rl = readline.createInterface({
input: fs.createReadStream(caminho),
crlfDelay: Infinity
});
const resultados = [];
for await (const linha of rl) {
// Processa cada linha individualmente
const dados = JSON.parse(linha);
if (dados.ativo) {
resultados.push(dados);
}
}
return resultados;
}
Uso de Array.from() com Objetos Iteráveis
// Convertendo Set em Array
const conjunto = new Set([1, 2, 3, 3, 4]);
const arrayUnico = Array.from(conjunto);
console.log(arrayUnico); // [1, 2, 3, 4]
// Convertendo Map em Array de pares
const mapa = new Map([['a', 1], ['b', 2]]);
const arrayPares = Array.from(mapa);
console.log(arrayPares); // [['a', 1], ['b', 2]]
// Usando o segundo argumento para transformar
const arrayTransformado = Array.from(mapa, ([chave, valor]) => ({
chave,
valor: valor * 2
}));
6. Arrays no React: Estado e Renderização
useState com Arrays – Imutabilidade e Spreads
import React, { useState } from 'react';
function ListaTarefas() {
const [tarefas, setTarefas] = useState([]);
// Adicionar tarefa (imutável)
const adicionarTarefa = (novaTarefa) => {
setTarefas(prev => [...prev, novaTarefa]);
};
// Remover tarefa (imutável)
const removerTarefa = (id) => {
setTarefas(prev => prev.filter(tarefa => tarefa.id !== id));
};
// Atualizar tarefa (imutável)
const atualizarTarefa = (id, novosDados) => {
setTarefas(prev => prev.map(tarefa =>
tarefa.id === id ? { ...tarefa, ...novosDados } : tarefa
));
};
}
Renderização de Listas com map() e key
function ListaUsuarios({ usuarios }) {
return (
<ul>
{usuarios.map(usuario => (
<li key={usuario.id}>
{usuario.nome} - {usuario.email}
</li>
))}
</ul>
);
}
// Nunca use o índice como key se a lista pode ser reordenada
// ❌ Ruim: {itens.map((item, index) => <Item key={index} />)}
// ✅ Bom: {itens.map(item => <Item key={item.id} />)}
Filtragem, Ordenação e Busca em Tempo Real com Hooks
import React, { useState, useMemo } from 'react';
function ListaProdutos({ produtos }) {
const [busca, setBusca] = useState('');
const [ordenacao, setOrdenacao] = useState('nome');
const produtosFiltrados = useMemo(() => {
return produtos
.filter(produto =>
produto.nome.toLowerCase().includes(busca.toLowerCase())
)
.sort((a, b) => {
if (ordenacao === 'nome') {
return a.nome.localeCompare(b.nome);
}
return a.preco - b.preco;
});
}, [produtos, busca, ordenacao]);
return (
<div>
<input
type="text"
value={busca}
onChange={e => setBusca(e.target.value)}
placeholder="Buscar produtos..."
/>
<select value={ordenacao} onChange={e => setOrdenacao(e.target.value)}>
<option value="nome">Nome</option>
<option value="preco">Preço</option>
</select>
{produtosFiltrados.map(produto => (
<div key={produto.id}>
{produto.nome} - R$ {produto.preco}
</div>
))}
</div>
);
}
7. Boas Práticas e Padrões Comuns
Evitando Mutações Diretas
// ❌ Mutação direta (pode causar bugs em React)
const arr = [1, 2, 3];
arr.push(4); // Muta o array original
arr.pop(); // Muta o array original
arr.splice(1, 1); // Muta o array original
// ✅ Cópias imutáveis
const novoArr = [...arr, 4]; // Adicionar no final
const novoArr2 = [0, ...arr]; // Adicionar no início
const novoArr3 = arr.slice(0, 2); // Remover elementos
const novoArr4 = arr.filter(x => x > 1); // Filtrar
const novoArr5 = arr.map(x => x * 2); // Transformar
Desestruturação de Arrays
// Desestruturação básica
const [primeiro, segundo, ...resto] = [1, 2, 3, 4, 5];
console.log(primeiro); // 1
console.log(segundo); // 2
console.log(resto); // [3, 4, 5]
// Trocando valores sem variável temporária
let a = 1, b = 2;
[a, b] = [b, a];
// Desestruturação em parâmetros de função
function calcularMedia([primeiro, segundo, ...resto]) {
const soma = primeiro + segundo + resto.reduce((acc, val) => acc + val, 0);
return soma / (2 + resto.length);
}
// Retornando múltiplos valores
function dividir(dividendo, divisor) {
return [Math.floor(dividendo / divisor), dividendo % divisor];
}
const [quociente, resto] = dividir(10, 3);
Encadeamento de Métodos
const usuarios = [
{ nome: 'Ana', idade: 25, ativo: true },
{ nome: 'João', idade: 17, ativo: true },
{ nome: 'Maria', idade: 30, ativo: false },
{ nome: 'Pedro', idade: 22, ativo: true }
];
// Encadeamento funcional - pipeline de transformação
const usuariosAtivosAdultos = usuarios
.filter(usuario => usuario.ativo && usuario.idade >= 18)
.map(usuario => ({
...usuario,
faixaEtaria: usuario.idade >= 60 ? 'idoso' : 'adulto'
}))
.sort((a, b) => a.idade - b.idade);
console.log(usuariosAtivosAdultos);
Referências
- MDN Web Docs: Array — Documentação completa sobre arrays em JavaScript, incluindo todos os métodos e propriedades.
- Node.js Documentation: Buffer — Guia oficial sobre o módulo Buffer do Node.js para manipulação de dados binários.
- React Documentation: Lists and Keys — Tutorial oficial do React sobre renderização de listas e importância das keys.
- JavaScript.info: Arrays — Guia completo e detalhado sobre arrays em JavaScript com exemplos práticos.
- Exploring JS: Array.from() and Array.of() — Capítulo do livro "Exploring ES6" sobre os métodos modernos de criação de arrays.