Entendendo o Object e o conceito de “objeto de objeto” em JavaScript
Os conceitos de objetos em JavaScript costumam gerar dúvidas, especialmente quando começamos a trabalhar com estruturas mais complexas, como “objetos de objetos” (objetos aninhados). Este artigo vai esclarecer:
– O que é o tipo primitivo `object` em JavaScript
– A diferença entre classe, instância e objeto
– O que é, na prática, um “objeto de objeto”
– Como acessar e manipular propriedades em objetos aninhados
– Boas práticas para trabalhar com esse tipo de estrutura
—
## 1. O que é um `object` em JavaScript?
Em JavaScript, quase tudo que não é um tipo primitivo básico (`string`, `number`, `boolean`, `null`, `undefined`, `symbol`, `bigint`) é um **objeto**.
De forma simplificada:
– Um **objeto** é uma coleção de pares **chave → valor**
– Essas chaves (propriedades) podem armazenar qualquer tipo de dado:
– valores primitivos
– funções
– outros objetos
Exemplo básico de objeto:
js
const usuario = {
nome: “Ana”,
idade: 28,
ativo: true
};
Aqui, `usuario` é um objeto do tipo `object` e possui três propriedades: `nome`, `idade` e `ativo`.
—
## 2. Classe vs instância vs objeto
Antes de entrar em “objeto de objeto”, vale alinhar conceitos que costumam se misturar:
– **Classe**: é um “molde” (ou modelo) que define a estrutura e comportamento de algo.
– **Instância**: é um “exemplar” concreto criado a partir dessa classe.
– **Objeto**: em JavaScript, a instância de uma classe é um objeto; mas também podemos criar objetos sem classe (via literal de objeto).
Exemplo com classe:
js
class Usuario {
constructor(nome, idade) {
this.nome = nome;
this.idade = idade;
}
saudacao() {
console.log(`Olá, meu nome é ${this.nome}`);
}
}
const ana = new Usuario(“Ana”, 28); // ana é uma instância de Usuario
// ana é um objeto
Exemplo sem classe (objeto literal):
js
const usuario = {
nome: “Ana”,
idade: 28,
saudacao() {
console.log(`Olá, meu nome é ${this.nome}`);
}
};
Nos dois casos estamos lidando, no fim, com um **objeto**. A grande diferença é a forma como esse objeto é criado.
—
## 3. O que é um “objeto de objeto” (objeto aninhado)?
“Objeto de objeto” nada mais é do que um **objeto que possui, em alguma de suas propriedades, outro objeto**.
Em outras palavras, é um **objeto aninhado** (nested object).
Exemplo:
js
const empresa = {
nome: “B2Bit”,
endereco: {
rua: “Av. Exemplo”,
numero: 123,
cidade: “São Paulo”,
estado: “SP”
}
};
– `empresa` é um objeto
– `endereco` também é um objeto
– `endereco` é uma propriedade de `empresa`
Portanto, `empresa` é um **objeto de objeto**: ele contém outro objeto dentro dele.
Este tipo de estrutura é extremamente comum quando lidamos com:
– Respostas de APIs (JSON)
– Modelagem de domínios mais complexos (usuários, pedidos, produtos, configurações, etc.)
—
## 4. Visualizando um objeto de objeto

Podemos pensar assim:
– Cada “caixa” é um objeto
– Dentro da caixa “pai” existe outra caixa, que também é um objeto
– O acesso é feito navegando por essas “caixas” através de suas chaves
—
## 5. Acessando propriedades em objetos aninhados
Com objetos simples:
js
const usuario = {
nome: “Ana”,
idade: 28
};
console.log(usuario.nome); // “Ana”
Com objetos de objetos:
js
const usuario = {
nome: “Ana”,
endereco: {
cidade: “São Paulo”,
estado: “SP”
}
};
console.log(usuario.endereco.cidade); // “São Paulo”
Também podemos acessar usando colchetes:
js
console.log(usuario[“endereco”][“cidade”]); // “São Paulo”
Essa sintaxe com colchetes é útil quando a chave está em uma variável:
js
const prop = “cidade”;
console.log(usuario.endereco[prop]); // “São Paulo”
—
## 6. Atualizando e criando propriedades em objetos aninhados
Para **atualizar**:
js
usuario.endereco.cidade = “Campinas”;
Para **criar** uma nova propriedade em um objeto interno:
js
usuario.endereco.cep = “00000-000”;
Se o objeto interno ainda não existir, primeiro você precisa criá-lo, senão receberá erro de acesso a `undefined`:
js
const usuario = {
nome: “Ana”
};
// usuario.endereco.cidade // ERRO: endereco é undefined
usuario.endereco = {}; // cria o objeto interno
usuario.endereco.cidade = “São Paulo”;
—
## 7. Profundidade de objetos: vários níveis de aninhamento
É possível ter mais de um nível de aninhamento:
js
const sistema = {
usuario: {
dadosPessoais: {
nome: “Ana”,
idade: 28
},
configuracoes: {
tema: “dark”,
notificacoes: true
}
}
};
Para acessar:
js
console.log(sistema.usuario.dadosPessoais.nome); // “Ana”
console.log(sistema.usuario.configuracoes.tema); // “dark”
Essa estrutura continua sendo apenas um grande objeto que contém outros objetos em várias camadas.
—
## 8. Lidando com erros ao acessar objetos aninhados
Um problema frequente é tentar acessar uma propriedade de algo que é `undefined`:
js
const usuario = {};
console.log(usuario.endereco.cidade);
// TypeError: Cannot read properties of undefined (reading ‘cidade’)
Porque `usuario.endereco` é `undefined`.
### 8.1. Operador de encadeamento opcional (`?.`)
O operador `?.` ajuda a evitar esse erro:
js
console.log(usuario.endereco?.cidade); // undefined (não quebra)
Se `endereco` for `undefined` ou `null`, a expressão é interrompida e retorna `undefined`.
Outro exemplo com vários níveis:
js
console.log(sistema.usuario?.dadosPessoais?.nome);
Se qualquer etapa no caminho for `undefined` ou `null`, o resultado será `undefined`, não um erro.
—
## 9. Copiando e clonando objetos de objetos
Outro ponto que costuma confundir é copiar objetos, especialmente quando há objetos internos.
### 9.1. Cópia por referência
Em JavaScript, objetos são copiados **por referência**, não por valor:
js
const endereco = {
cidade: “São Paulo”,
estado: “SP”
};
const endereco2 = endereco;
endereco2.cidade = “Campinas”;
console.log(endereco.cidade); // “Campinas”
`endereco` e `endereco2` apontam para o mesmo objeto na memória.
### 9.2. Cópia rasa (shallow copy)
Usando o operador spread (`…`), você faz uma cópia **apenas do primeiro nível**:
js
const usuario = {
nome: “Ana”,
endereco: {
cidade: “São Paulo”,
estado: “SP”
}
};
const copia = { …usuario };
copia.nome = “João”; // muda só em ‘copia’
copia.endereco.cidade = “Campinas”; // afeta usuario.endereco também
console.log(usuario.endereco.cidade); // “Campinas”
A propriedade `endereco` continua sendo o mesmo objeto em ambos.
### 9.3. Cópia profunda (deep copy)
Para copiar também os objetos internos, precisamos de uma **cópia profunda**. Uma forma simples (embora com limitações) é:
js
const copiaProfunda = JSON.parse(JSON.stringify(usuario));
Isso cria novos objetos em todos os níveis, mas não lida bem com funções, `Date`, `Map`, `Set` etc. Para casos mais complexos, usam-se bibliotecas específicas ou implementações próprias.
—
## 10. Objetos de objetos em respostas de API (JSON)
Muitos dados trafegam na web em formato JSON, que é essencialmente **texto representando objetos e arrays**, frequentemente com objetos aninhados.
Por exemplo, uma API pode retornar algo assim:
json
{
“usuario”: {
“id”: 1,
“nome”: “Ana”,
“endereco”: {
“cidade”: “São Paulo”,
“estado”: “SP”
}
}
}
Ao receber essa resposta em JavaScript (depois de fazer `JSON.parse()` ou usando `response.json()` no `fetch`), você terá um **objeto de objeto** exatamente como vimos:
js
const dados = {
usuario: {
id: 1,
nome: “Ana”,
endereco: {
cidade: “São Paulo”,
estado: “SP”
}
}
};
console.log(dados.usuario.endereco.cidade); // “São Paulo”
—
## 11. Boas práticas ao trabalhar com objetos aninhados
### 11.1. Evite aninhamento excessivo
Objetos com muitos níveis dificultam a leitura e manutenção:
js
// Evite algo assim:
sistema.usuario.configuracoes.interface.tema.cores.primaria;
Considere:
– Quebrar em estruturas menores
– Criar funções de acesso
– Normalizar dados, dependendo do caso
### 11.2. Use destructuring para simplificar
O **destructuring** ajuda a “desmontar” objetos aninhados:
js
const sistema = {
usuario: {
dadosPessoais: {
nome: “Ana”,
idade: 28
}
}
};
const { usuario: { dadosPessoais: { nome, idade } } } = sistema;
console.log(nome); // “Ana”
console.log(idade); // 28
Com `?.`:
js
const nomeUsuario = sistema.usuario?.dadosPessoais?.nome ?? “Desconhecido”;
### 11.3. Valide antes de acessar
Mesmo sem `?.`, você pode validar manualmente:
js
if (usuario && usuario.endereco && usuario.endereco.cidade) {
console.log(usuario.endereco.cidade);
}
—
## 12. Representando visualmente objetos aninhados

Ver objetos aninhados como “camadas” ou “caixas dentro de caixas” ajuda a entender:
– Cada camada é um objeto
– Cada chave aponta para um valor, que pode ser outro objeto
– Navegar até uma informação é seguir esse caminho de chaves
—
## 13. Resumo
– Em JavaScript, `object` é um tipo que representa coleções de pares chave → valor.
– Um **objeto de objeto** é apenas um objeto que contém outro objeto em uma de suas propriedades.
– Acesso a objetos aninhados é feito encadeando chaves: `obj.chave1.chave2…`.
– É preciso ter cuidado com:
– Acesso a propriedades de valores `undefined`
– Cópia de objetos (referência vs cópia rasa vs cópia profunda)
– Ferramentas como `?.`, destructuring e uma boa modelagem de dados ajudam a manter o código mais seguro, legível e fácil de manter.
Entender bem esses conceitos é fundamental para trabalhar com dados estruturados em JavaScript, especialmente quando você lida com APIs, configurações complexas e modelagem de domínios de negócio.