Dia 9 — Objetos

Informatica · Conteudo · publicado em 02/10/2026
Aula 1

Criar e acessar propriedades

Objeto: a estrutura chave-valor

Objeto é o dicionário do JavaScript: cada propriedade é um par de chave e valor. Enquanto o array guarda itens em ordem, numerados a partir de 0, o objeto guarda o que se procura por nome. Um cadastro, uma linha de tabela, a resposta de uma API e a configuração de um programa são todos objetos.

A forma curta é {} com pares chave: valor separados por vírgula. A forma longa, new Object(), continua válida e quase nunca é usada.

const aluno = {
  id: 1,
  nome: 'Ana Souza',
  ativo: true,
};

Chave pode ser qualquer string, com espaço e acento, desde que esteja entre aspas. Valor é qualquer coisa: número, texto, true, null, outro objeto, um array ou uma função.

A forma de criar objeto é a chave dentro das chaves: { nome: 'Ana' }. O [] cria lista; o {} cria o que o material chama de objeto, e cada par dentro dele é a propriedade — chave e valor.

Notação de ponto e notação de colchete

As duas notações fazem a mesma coisa. A de ponto é a mais curta e serve quando a chave é um identificador válido; a de colchete é a forma geral e aceita qualquer texto como chave.

const aluno = { nome: 'Ana', email: '[email protected]' };

aluno.nome;              // 'Ana'
aluno['email'];          // '[email protected]'

const campo = 'email';
aluno[campo];            // '[email protected]'

A notação de colchete é a única que funciona com chave que vem de uma variável. aluno[campo] funciona; aluno.campo não existe, porque a chave escrita com ponto vira o nome literal campo. É isso que faz a chave dinamica: o nome vem de fora, decidido em tempo de execução, e o objeto só é consultado depois.

NotaçãoAssinaturaQuando usar
pontoobjeto.propriedadechave fixa, sem espaço e que começa por letra
colcheteobjeto['propriedade']chave com espaço, acento ou pontuação
colchete com variávelobjeto[variavel]chave escolhida em tempo de execução

A segunda linha da tabela é a notação de colchete com a chave entre aspas: objeto["propriedade"], que é a forma geral e aceita qualquer texto — inclusive a chave que tem espaço dentro.

Uma chave que começa com número ('1') ou que é palavra reservada ('class') só funciona com colchete e com aspas. objeto.class é erro de sintaxe.

Criar, alterar e remover propriedades

Não existe declaração de propriedade: o objeto nasce com o que foi escrito e aceita propriedade nova a qualquer momento. As duas notações também escrevem.

const contato = {};

contato.telefone = '(81) 99999-0000';   // cria com ponto
contato['cidade'] = 'Recife';           // cria com colchete
delete contato.cidade;                  // remove e devolve true

delete devolve true quando conseguiu apagar e false quando a propriedade não existia. Não há como desfazer: apagar a chave não guarda o valor em lugar nenhum.

Propriedade que não existe não é erro. aluno.cpf devolve undefined, e o programa segue rodando como se a chave tivesse valor vazio.

const aluno = { nome: 'Ana' };

aluno.cpf;              // undefined
typeof aluno.cpf;       // 'undefined'
'aluno.cpf' in aluno;   // false — a chave não está lá

Esse silêncio é a origem de bug mais comum da linguagem: código que assume que a propriedade existe recebe undefined em vez de um aviso, e o TypeError só aparece mais abaixo, na linha que tentou usar o valor.

Copiar o objeto

Atribuição não copia. Copia a referência: as duas variáveis passam a apontar para o mesmo objeto, e mexer em uma muda a outra.

const original = { nome: 'Ana' };
const copia = original;

copia.nome = 'Bruno';
original.nome;   // 'Bruno' — mudou junto

Para copiar de verdade, use o spread dentro de {}, que monta um objeto novo com as mesmas propriedades.

const original = { nome: 'Ana', cidade: 'Recife' };
const copia = { ...original };

copia.nome = 'Bruno';
original.nome;   // 'Ana' — o original ficou como estava

O spread é raso: as propriedades que são objetos ou arrays continuam apontando para o mesmo lugar. Copiar { ...produto } duplica a casca, e o produto.medidas continua sendo o mesmo objeto nos dois. Para clonar um nível a mais é preciso structuredClone, que funciona com objeto, array, Map, Set e Date.

const não protege o conteúdo do objeto: const ficha = { ativo: true } permite ficha.ativo = false, porque o const trava a variável, não o que está dentro dela. Quando a intenção é travar o conteúdo, o caminho é Object.freeze, que impede a escrita no próprio nível — e só nele.

Ler propriedade de undefined ou de null é TypeError na hora: usuario.nome com usuario inexistente quebra o programa. A leitura de propriedade inexistente em objeto que existe é silenciosa; a leitura em valor que não existe, não.

Exemplo

'use strict';
// ============================================================
// AULA 1 - Objeto: criar, acessar e remover propriedades
//
// O objeto é o dicionário do JavaScript: chave, valor. Este
// exemplo mostra a forma curta, as duas notações de acesso, a
// atribuição de propriedade nova e o `delete`.
// ============================================================

// A forma curta: cada par é `chave: valor`, separado por vírgula.
const aluno = {
  id: 1,
  nome: 'Ana Souza',
  email: '[email protected]',
  ativo: true,
};

// Notação de ponto: a mais curta, para chave que é identificador válido.
console.log('aluno.nome  :', aluno.nome);
console.log('aluno.ativo :', aluno.ativo);

// Notação de colchete: a forma geral, aceita qualquer chave como texto.
console.log("aluno['email']:", aluno['email']);

// Com colchete a chave pode vir de uma variável. Com ponto, não.
const campo = 'email';
console.log('aluno[campo] :', aluno[campo]);

// Atribuir propriedade que ainda não existia: nada precisa ser declarado
// antes. As duas notações também escrevem.
aluno.cidade = 'Recife';
aluno['nota'] = 8.5;
console.log('\nchaves depois das duas atribuições:', Object.keys(aluno).join(', '));

// Objeto vazio e preenchido depois, campo a campo.
const contato = {};
contato.telefone = '(81) 99999-0000';
contato['cidade'] = 'Recife';
console.log('contato.telefone:', contato.telefone);

// Propriedade inexistente NÃO dá erro: devolve `undefined`.
console.log('\naluno.cpf (não existe)  ->', aluno.cpf);
console.log('typeof aluno.cpf         ->', typeof aluno.cpf);

// A mesma chave em dois objetos guarda valores independentes.
const outro = { nome: 'Bruno Lima', email: '[email protected]' };
console.log('\nmesma chave, dois objetos:', aluno.nome, '|', outro.nome);

// `delete` remove e devolve `true`. Não existe como desfazer.
const apagado = delete aluno.ativo;
console.log('\ndelete aluno.ativo devolveu:', apagado);
console.log('chaves depois do delete:', Object.keys(aluno).join(', '));

// Cópia com o spread: objeto novo, o original intacto.
const copia = { ...aluno };
copia.nome = 'Carla Dias';
console.log('\ndepois de editar a cópia -> cópia:', copia.nome, '| original:', aluno.nome);

// Ler propriedade de algo que não é objeto é `TypeError`. É o erro que
// trava mais formulário: o `value` do campo veio vazio e o código tentou
// ler `.length` em `undefined`. O aviso vai para o stderr e o programa
// continua rodando depois dele.
console.log('\n--- o que acontece quando o objeto não existe ---');
try {
  const usuario = undefined;
  console.log(usuario.nome);
} catch (erro) {
  console.error(erro.constructor.name + ': ' + erro.message);
}
console.log('--- o código depois do erro continua rodando ---');

Saída real

aluno.nome  : Ana Souza
aluno.ativo : true
aluno['email']: [email protected]
aluno[campo] : [email protected]

chaves depois das duas atribuições: id, nome, email, ativo, cidade, nota
contato.telefone: (81) 99999-0000

aluno.cpf (não existe)  -> undefined
typeof aluno.cpf         -> undefined

mesma chave, dois objetos: Ana Souza | Bruno Lima

delete aluno.ativo devolveu: true
chaves depois do delete: id, nome, email, cidade, nota

depois de editar a cópia -> cópia: Carla Dias | original: Ana Souza

--- o que acontece quando o objeto não existe ---
--- o código depois do erro continua rodando ---
Aula 2

Desestruturacao e os metodos de objeto

Ler o objeto inteiro

Quando a chave é desconhecida — um relatório, uma validação, um formulário montado a partir de dados — o que se procura são as três listas: as chaves, os valores, ou os pares.

MétodoAssinaturaDevolve
Object.keysObject.keys(objeto)array com as chaves, na ordem de inserção
Object.valuesObject.values(objeto)array com os valores, na mesma ordem
Object.entriesObject.entries(objeto)array de pares [chave, valor]
Object.fromEntriesObject.fromEntries([[chave, valor]])o caminho inverso: pares viram objeto
const ficha = { id: 7, nome: 'Cadeira', preco: 749.9 };

Object.keys(ficha);     // ['id', 'nome', 'preco']
Object.values(ficha);   // [7, 'Cadeira', 749.9]
Object.entries(ficha);  // [['id', 7], ['nome', 'Cadeira'], ['preco', 749.9]]

Os três devolvem arrays novos. Mexer no array devolvido não altera o objeto, e recarregar Object.keys depois devolve a lista de novo, sem o que foi acrescentado.

O entries é o que percorre com for...of: cada volta entrega um par, que a desestruturação quebra em duas variáveis.

for (const [chave, valor] of Object.entries(ficha)) {
  console.log(chave, '=', valor);
}

A ordem é sempre a de inserção para chave que não parece número. Chave que é a string '2' ou '1' vem antes das outras, porque o JavaScript trata chave numérica como índice e as coloca em ordem crescente. Para chaves em ordem previsível, use prefixo: 'campo_nome'.

Desestruturação

A desestruturação entrega as propriedades do objeto em variáveis, sem escrever o nome do objeto em cada linha. É a forma curta de "pegue estes campos". O termo em inglês é destructure, e o que ele faz é o oposto do spread: o spread junta, a desestruturação separa.

const { nome, preco } = ficha;
console.log(nome, preco);

Três variações resolvem os três casos que aparecem:

FormaO que faz
{ nome }a variável nome recebe ficha.nome
{ nome: titulo }renomeia: a variável titulo recebe ficha.nome
{ desconto = 0 }valor padrão quando a chave não existe
const { nome: titulo, desconto = 0 } = ficha;

O padrão só age quando a chave está ausente ou vale undefined. Se a chave existir com valor 0, o 0 é o que fica.

Para objeto aninhado, a desestruturação desce em dois níveis, e o nome do nível intermediário não precisa de variável:

const { medidas: { largura } } = produto;

Para o resto, use o resto: const { nome, ...resto } = ficha tira nome e entrega todo o resto em resto, que é um objeto novo.

Mesclar objetos

Object.assign e o spread juntam dois objetos num terceiro. A chave repetida do segundo ganha, e o resultado é sempre objeto novo. O spread em objeto é o mesmo ... do dia 7: aqui ele vai dentro das chaves e copia as propriedades.

FormaAssinaturaCuidado
spread{ ...padrao, ...doUsuario }devolve objeto novo
assignObject.assign(alvo, ...fonte)mexe no alvo, que é o primeiro argumento
const padrao = { tema: 'claro', fonte: 16, idioma: 'pt-BR' };
const doUsuario = { tema: 'escuro' };

const tema = { ...padrao, ...doUsuario };   // tema: 'escuro'

Object.assign(padrao, doUsuario) tem o mesmo efeito no conteúdo, mas altera padrao para sempre — e padrao foi declarado com const, o que não impede nada aqui. Para mesclar sem efeito colateral, o primeiro argumento precisa ser {}.

Object.assign só copia propriedades próprias e enumeráveis. Método definido no objeto também é copiado como valor, mas JSON.stringify não o serializa.

O método abreviado é o que dispensa o par nome: nome no objeto. Com a forma longa, nome: nome e somar: function(a, b) { }; com a abreviada, somar(a, b) { } — o mesmo resultado, e o objeto fica legível.

const calculadora = {
  somar(a, b) { return a + b; },          // método abreviado
  somarAntigo: function (a, b) { return a + b; },  // a forma longa
};

Verificar e travar

Antes de perguntar se a chave existe, vale saber o que a chave vale. O typeof objeto devolve 'object' para objeto, array, função, null e Date — todos eles. A única diferença entre eles é o que Array.isArray e instanceof respondem; o typeof sozinho não separa nada.

MétodoAssinaturaDevolve
in'chave' in objetotrue se a chave existe, inclusive as herdadas
Object.hasOwnObject.hasOwn(objeto, 'chave')true só se a chave é do próprio objeto
hasOwnPropertyobjeto.hasOwnProperty('chave')o mesmo; é o método antigo
Object.freezeObject.freeze(objeto)trava a escrita no próprio nível
'preco' in ficha;                 // true
'toString' in {};                // true — veio do protótipo
Object.hasOwn({}, 'toString');   // false

in e hasOwn discordam justamente nos métodos que todo objeto tem herdados: toString, constructor, hasOwnProperty. Para perguntar se o dado está no objeto, Object.hasOwn é a resposta certa.

Object.freeze impede escrita nas propriedades dele. Com 'use strict' no topo do arquivo, a tentativa de escrever lança TypeError; sem o modo estrito, a escrita é ignorada em silêncio.

ChamadaEfeito
Object.freeze(objeto)trava o nível de fora
Object.isFrozen(objeto)true se o próprio nível está travado
Object.seal(objeto)não aceita chave nova, mas aceita alterar valor
Object.freeze com objeto dentroo interno continua mutável, é raso

JSON: o objeto indo e voltando pela rede

JSON.stringify transforma objeto em texto e JSON.parse traz o texto de volta. É o que toda comunicação entre o navegador e o servidor faz, e o que o localStorage usa para guardar objeto.

FunçãoAssinaturaDevolve
stringifyJSON.stringify(objeto, filtro, espaco)texto
parseJSON.parse(texto)objeto
parse com padrãoJSON.parse(texto, reviver)objeto, com função de transformação
const linha = JSON.stringify(ficha, null, 2);
const deVolta = JSON.parse(linha);

O segundo argumento é o filtro de propriedades e o terceiro é a indentação, em espaços. null no lugar do filtro significa "todos"; um array de nomes de chave inclui só essas.

O que o JSON não leva: função, undefined, símbolo e Date vira texto. A função é simplesmente ignorada, sem erro e sem aviso — o objeto serializado sai menor do que o original, e o código que dependia do método só quebra depois, do outro lado da rede.

Texto que não é JSON válido é SyntaxError no parse, e o objeto que se obtinha antes da chamada se perde.

localStorage só aceita texto. localStorage.setItem('user', objeto) grava a palavra [object Object], que volta inútil no getItem. O caminho é setItem('user', JSON.stringify(objeto)) e JSON.parse(getItem('user')) na leitura — e o try/catch em volta, porque um dado gravado por uma versão antiga do código pode não ser mais parseável.

JSON.stringify e JSON.parse não são o mesmo que structuredClone: o segundo copia Date, Map e Set e mantém o tipo, o que o JSON não consegue. Para mandar dado a um servidor, o formato é JSON; para clonar objeto dentro do próprio programa, é structuredClone.

Exemplo

'use strict';
// ============================================================
// AULA 2 - Desestruturação e os métodos que leem o objeto
//
// `Object.keys`, `Object.values` e `Object.entries` leem o objeto
// inteiro; a desestruturação entrega as propriedades em variáveis;
// `assign` e spread mesclam; `freeze` trava; `JSON` vai e volta
// pela rede.
// ============================================================

// Registro simples, o mais comum do dia a dia.
const ficha = {
  id: 7,
  nome: 'Cadeira de escritorio',
  preco: 749.9,
  ativo: true,
};

// --- Ler o objeto inteiro ---
console.log('keys   :', Object.keys(ficha));
console.log('values :', Object.values(ficha));
console.log('entries:', Object.entries(ficha));

// `for...of` sobre `entries`: chave e valor na mesma volta do laço.
console.log('\npares chave/valor:');
for (const [chave, valor] of Object.entries(ficha)) {
  console.log(`  ${chave} = ${valor}`);
}

// Os três devolvem array NOVO: mexer no array não mexe no objeto.
const chaves = Object.keys(ficha);
chaves.push('sorteado');
console.log('\narray devolvido é novo:', chaves.length, 'itens, o objeto continua com',
  Object.keys(ficha).length, 'chaves');

// --- Desestruturação ---
const { nome, preco } = ficha;
console.log('\nnome:', nome, '| preco:', preco);

// Com ':' a variável ganha outro nome.
const { nome: nomeDoProduto } = ficha;
console.log('variável renomeada, nomeDoProduto:', nomeDoProduto);

// Com '=' vem o valor padrão, usado quando a chave não existe.
const { desconto = 0 } = ficha;
console.log('desconto padrão quando a chave não existe:', desconto);

// Desestruturar junto com o objeto aninhado.
const produto = {
  codigo: 'C-100',
  medidas: { largura: 60, altura: 110 },
  descrever() {
    return `${this.codigo}: ${this.medidas.largura}x${this.medidas.altura} cm`;
  },
};
const { medidas: { altura } } = produto;
console.log('altura vinda do objeto aninhado:', altura);
console.log('método do objeto:', produto.descrever());

// --- Mesclar e travar ---
const padrao = { tema: 'claro', fonte: 16, idioma: 'pt-BR' };
const doUsuario = { tema: 'escuro' };

// `assign` MODIFICA o primeiro argumento e devolve.
// Com `{}` no lugar do `padrao`, o original fica intacto.
const porAssign = Object.assign({}, padrao, doUsuario);
console.log('\nmesclado:', porAssign);

// O spread faz a mesma coisa sem depender de efeito colateral.
const porSpread = { ...padrao, ...doUsuario };
console.log('mesclado com spread:', porSpread);
console.log('o padrão continua intacto:', JSON.stringify(padrao));

// `freeze` trava o nível de fora. Com `'use strict'` a escrita em objeto
// congelado lança `TypeError` em vez de ser ignorada em silêncio.
const congelado = Object.freeze({ versao: 1, tags: ['js', 'web'] });
try {
  congelado.versao = 2;
} catch (erro) {
  console.error('tentou escrever no congelado -> ' + erro.constructor.name);
}
// O `freeze` é RASO: `tags` é um array, ou seja, outro nível, e passa.
congelado.tags.push('dom');
console.log('\nfreeze raso: versão continua', congelado.versao,
  '| tags, que são outro nível:', congelado.tags.join(', '));

// --- Verificar e serializar ---
console.log('\n"preco" in ficha        :', 'preco' in ficha);
console.log('"toString" in {}        :', 'toString' in {}, '(vem do protótipo)');
console.log('Object.hasOwn({}, "toString"):', Object.hasOwn({}, 'toString'));

// `JSON.stringify` vira texto; o terceiro argumento indenta.
const linha = JSON.stringify(ficha, null, 2);
console.log('\ntexto gerado:');
console.log(linha);

// `JSON.parse` volta para objeto. É o caminho de todo `fetch` e
// do `localStorage`.
const deVolta = JSON.parse(linha);
console.log('type:', typeof deVolta, '| deVolta.preco:', deVolta.preco);

// Função não vai para o JSON: é preciso montar o que será enviado.
const comMetodo = JSON.stringify(produto, null, 2);
console.log('\nJSON do objeto com método:\n' + comMetodo);

Saída real

keys   : [ 'id', 'nome', 'preco', 'ativo' ]
values : [ 7, 'Cadeira de escritorio', 749.9, true ]
entries: [
  [ 'id', 7 ],
  [ 'nome', 'Cadeira de escritorio' ],
  [ 'preco', 749.9 ],
  [ 'ativo', true ]
]

pares chave/valor:
  id = 7
  nome = Cadeira de escritorio
  preco = 749.9
  ativo = true

array devolvido é novo: 5 itens, o objeto continua com 4 chaves

nome: Cadeira de escritorio | preco: 749.9
variável renomeada, nomeDoProduto: Cadeira de escritorio
desconto padrão quando a chave não existe: 0
altura vinda do objeto aninhado: 110
método do objeto: C-100: 60x110 cm

mesclado: { tema: 'escuro', fonte: 16, idioma: 'pt-BR' }
mesclado com spread: { tema: 'escuro', fonte: 16, idioma: 'pt-BR' }
o padrão continua intacto: {"tema":"claro","fonte":16,"idioma":"pt-BR"}

freeze raso: versão continua 1 | tags, que são outro nível: js, web, dom

"preco" in ficha        : true
"toString" in {}        : true (vem do protótipo)
Object.hasOwn({}, "toString"): false

texto gerado:
{
  "id": 7,
  "nome": "Cadeira de escritorio",
  "preco": 749.9,
  "ativo": true
}
type: object | deVolta.preco: 749.9

JSON do objeto com método:
{
  "codigo": "C-100",
  "medidas": {
    "largura": 60,
    "altura": 110
  }
}