Manipulando objetos
Esta aula aborda técnicas avançadas de manipulação de objetos em JavaScript, incluindo métodos estáticos como Object.keys/values/entries, operador spread, Object.freeze e a diferença entre cópia rasa e profunda. Com exemplos práticos, você aprenderá a percorrer, clonar e proteger objetos de forma eficiente.
Objetos são estruturas fundamentais em JavaScript, usados para armazenar dados de forma organizada. Nesta aula, vamos explorar técnicas poderosas para manipulá-los: desde a extração de chaves e valores até a clonagem e proteção contra modificações. Compreender esses conceitos é essencial para escrever código robusto e previsível.
Vamos começar com métodos estáticos do objeto Object que nos permitem iterar sobre propriedades, depois veremos como o operador spread simplifica a cópia e mesclagem de objetos. Em seguida, aprenderemos a congelar objetos com Object.freeze e, por fim, a crucial diferença entre cópia rasa e profunda.
Object.keys/values/entries
Os métodos Object.keys(), Object.values() e Object.entries() são ferramentas essenciais para trabalhar com objetos de forma iterativa. Eles retornam arrays contendo, respectivamente, as chaves, os valores ou pares chave-valor de um objeto. Esses métodos são particularmente úteis para percorrer objetos com loops ou para transformar dados.
Exemplo prático: suponha que você tenha um objeto representando um produto e queira listar todas as suas propriedades.
const produto = {
nome: 'Notebook',
preco: 3500,
emEstoque: true
};
console.log(Object.keys(produto)); // ['nome', 'preco', 'emEstoque']
console.log(Object.values(produto)); // ['Notebook', 3500, true]
console.log(Object.entries(produto));
// [['nome', 'Notebook'], ['preco', 3500], ['emEstoque', true]]
Você pode usar Object.entries() com um loop for...of para iterar sobre chaves e valores simultaneamente:
for (const [chave, valor] of Object.entries(produto)) {
console.log(`${chave}: ${valor}`);
}
// nome: Notebook
// preco: 3500
// emEstoque: true
Spread em objetos
O operador spread (...) foi introduzido no ES2018 para objetos, permitindo copiar propriedades de um objeto para outro de forma concisa. É amplamente usado para clonagem rasa e mesclagem de objetos.
Exemplo básico de clonagem:
const original = { a: 1, b: 2 };
const copia = { ...original };
console.log(copia); // { a: 1, b: 2 }
console.log(copia === original); // false
Spread também permite sobrescrever propriedades ou adicionar novas:
const usuario = { nome: 'João', idade: 30 };
const usuarioAtualizado = { ...usuario, idade: 31, email: 'joao@email.com' };
console.log(usuarioAtualizado);
// { nome: 'João', idade: 31, email: 'joao@email.com' }
Importante: a ordem importa. Propriedades posteriores sobrescrevem as anteriores.
Freeze
Object.freeze() impede que um objeto seja modificado: não é possível adicionar, remover ou alterar propriedades existentes. É útil para criar constantes ou garantir imutabilidade.
const config = { api: 'https://api.exemplo.com', timeout: 5000 };
Object.freeze(config);
config.timeout = 6000; // Ignorado em modo estrito, lança erro em strict mode
console.log(config.timeout); // 5000
No entanto, Object.freeze é raso: se o objeto contiver objetos aninhados, eles ainda podem ser modificados. Para congelamento profundo, é necessário implementar recursão ou usar bibliotecas como deep-freeze.
const dados = { nivel1: { nivel2: 'valor' } };
Object.freeze(dados);
dados.nivel1.nivel2 = 'novo valor'; // Permitido!
console.log(dados.nivel1.nivel2); // 'novo valor'
Cópia rasa vs profunda
Ao copiar objetos, precisamos entender a diferença entre cópia rasa (shallow copy) e cópia profunda (deep copy). Uma cópia rasa duplica apenas as propriedades do primeiro nível; para propriedades que são objetos, a referência é copiada, não o objeto em si. Já a cópia profunda cria uma duplicata independente de toda a hierarquia.
Exemplo de cópia rasa usando spread:
const original = { a: 1, b: { c: 2 } };
const copiaRasa = { ...original };
copiaRasa.b.c = 3;
console.log(original.b.c); // 3 (afetou o original)
Para cópia profunda, uma abordagem comum é usar JSON.parse(JSON.stringify(obj)), mas ela tem limitações (não suporta funções, undefined, símbolos, etc.).
const copiaProfunda = JSON.parse(JSON.stringify(original));
copiaProfunda.b.c = 4;
console.log(original.b.c); // 3 (não afetou)
Alternativas modernas incluem structuredClone() (navegadores e Node.js 17+) e bibliotecas como Lodash (_.cloneDeep).
Boas práticas
- Prefira imutabilidade sempre que possível: crie novos objetos em vez de modificar os existentes.
- Use
Object.freezepara configs e constantes que não devem ser alteradas. - Ao copiar objetos, escolha o método adequado: spread para cópia rasa simples,
structuredClonepara cópia profunda confiável. - Evite
JSON.parse(JSON.stringify(obj))para objetos com funções, datas ou referências circulares.
Referências
- MDN: Object.keys()
- MDN: Object.values()
- MDN: Object.entries()
- MDN: Spread syntax
- MDN: Object.freeze()
- MDN: structuredClone()
- Lodash: _.cloneDeep
Exercícios
-
Exercício 1: Dado o objeto
carro = { marca: 'Fiat', modelo: 'Uno', ano: 2020 }, useObject.valuespara obter um array com os valores e exiba no console.✓ Resposta:const carro = { marca: 'Fiat', modelo: 'Uno', ano: 2020 }; console.log(Object.values(carro)); // ['Fiat', 'Uno', 2020] -
Exercício 2: Use o operador spread para criar um novo objeto
carro2que copie todas as propriedades decarroe altere o ano para 2022.✓ Resposta:const carro2 = { ...carro, ano: 2022 }; console.log(carro2); // { marca: 'Fiat', modelo: 'Uno', ano: 2022 } -
Exercício 3: Congele o objeto
carrocomObject.freezee tente alterar a propriedademarca. Verifique se a alteração foi ignorada.✓ Resposta:Object.freeze(carro); carro.marca = 'Chevrolet'; console.log(carro.marca); // 'Fiat' (alteração ignorada) -
Exercício 4: Dado o objeto
pessoa = { nome: 'Ana', endereco: { cidade: 'SP', rua: 'A' } }, faça uma cópia rasa usando spread e altere a cidade na cópia. A cidade do objeto original também foi alterada? Explique.✓ Resposta:const pessoa = { nome: 'Ana', endereco: { cidade: 'SP', rua: 'A' } }; const copia = { ...pessoa }; copia.endereco.cidade = 'RJ'; console.log(pessoa.endereco.cidade); // 'RJ' (sim, foi alterado porque a cópia é rasa) -
Exercício 5: Use
JSON.parse(JSON.stringify())para fazer uma cópia profunda do objetopessoa. Altere a rua na cópia e verifique se o original permanece inalterado.✓ Resposta:const copiaProfunda = JSON.parse(JSON.stringify(pessoa)); copiaProfunda.endereco.rua = 'B'; console.log(pessoa.endereco.rua); // 'A' (original não foi alterado)