Dia 9 — Objetos e desestruturação

Informatica · Conteudo · publicado em 05/10/2026
Dia 9 de 13

Objetos e desestruturação

Aula 1

Objetos: propriedades, métodos e o this

Objetos: propriedades, métodos e o this

Um objeto é uma coleção de pares chave e valor. As propriedades são os

valores nomeados; o método é uma propriedade que guarda função. Em React

Native, objeto é o formato de quase todo dado que chega da API e o formato do

estado de um componente.

const usuario = { nome: 'Ana', idade: 30 };
console.log(usuario.nome);        // 'Ana'

O objeto literal é o que está entre {}: é a forma curta, e é a que se usa

sempre. A notação de ponto é usuario.nome; a notação de colchete é

usuario['nome'], e as duas dão o mesmo resultado. O colchete é o necessário

quando o nome da propriedade vem de uma variável:

const campo = 'idade';
console.log(usuario[campo]);      // 30

O exemplo do objeto tem quatro propriedades — nome, idade, ativo e o

método saudar — e a primeira linha sai ponto: Ana | colchete: Ana: as duas

notações na mesma linha, com o mesmo resultado. A linha seguinte usa a variável

no colchete e sai colchete com variavel: 30, que é a razão de o colchete

existir: com o ponto, usuario.campo leria a propriedade chamada campo, e

não a que está dentro da variável.

O objeto da API tem erro: null ao lado dos dados, e isso aparece no fim do

exemplo: da api: 1 tarefa | erro: null. A mesma resposta traz o resultado e o

motivo de não ter resultado, e é assim que o app decide o que desenhar.

Propriedade que não existe

Ler uma propriedade ausente devolve undefined — não é erro. Escrever uma

propriedade nova cria a chave:

console.log(usuario.email);        // undefined
usuario.email = '[email protected]'; // cria a chave

O teste de existência tem duas formas, e a diferença importa:

console.log('nome' in usuario);            // true
console.log(usuario.email !== undefined); // false: a chave existe com valor undefined

A forma in pergunta pela chave; a comparação pergunta pelo valor. Chave

existente com valor undefined existe.

Para apagar, delete:

delete usuario.email;

As quatro linhas do exemplo mostram a propriedade ausente e as duas formas de

testá-la. email: undefined é a leitura que não é erro, e

depois de escrever: [email protected] é a chave criada pela atribuição. Depois,

'apelido' in objeto: true ao lado de apelido !== undefined: false — o mesmo

objeto com apelido: undefined, e as duas perguntas discordando.

O par é a diferença do parágrafo: a chave existe, o valor é undefined. Quem

quiser saber se pode usar o campo consulta o valor; quem quiser saber se a

chave foi removida consulta a chave.

O delete fecha o ciclo, e a saída é

depois do delete: [ 'nome', 'idade', 'ativo', 'saudar' ]. O email sumiu da

lista de chaves, e o que ficou é tudo o mais — inclusive saudar, o método.

É essa linha que mostra que o objeto tem quatro propriedades e não três, e que

delete removeu uma só.

Os três métodos que listam um objeto

Object.keys(usuario);     // ['nome', 'idade']
Object.values(usuario);   // ['Ana', 30]
Object.entries(usuario);  // [['nome', 'Ana'], ['idade', 30]]

Os três devolvem array, e por isso entram direto em map e filter. É assim

que a tela monta uma lista de linhas a partir de um objeto que veio da API:

Object.entries(usuario).map(([chave, valor]) => `${chave}: ${valor}`);

As três linhas do exemplo são keys: [ 'nome', 'idade', 'ativo', 'saudar' ],

values: [ 'Ana', 30, true, [Function: saudar] ] e o entries em quatro pares.

Repare que o método saudar aparece nos três: Object.keys devolve o nome dele,

Object.values devolve a função, e Object.entries devolve o par com os dois.

Quem quiser só os dados, sem método, precisa filtrar — e o filtro é por

typeof.

O entries com map do exemplo sai nome: Ana | idade: 30 sobre um objeto de

duas propriedades, e é a linha que mostra o uso da desestruturação do par:

([chave, valor]) são dois nomes recebidos do array de dois itens que cada

entrada é.

O this: o que é e quando existe

this é o objeto que chamou o método, e só existe dentro de uma função que foi

chamada como método:

const contador = {
  total: 0,
  somar(n) {
    this.total += n;
    return this.total;
  },
};
contador.somar(5);   // 5

O this é o que permite o mesmo método servir para vários objetos: cada chamada

this é o objeto daquela chamada. Se o método for guardado numa variável e

chamado sem o objeto na frente — const somar = contador.somar; somar(1) —, o

this deixa de ser o contador. Em arquivo .js comum, o que acontece é pior que

erro: o this vira o objeto global, a conta sai NaN e nada acusa. O

contador original nem é tocado. Por isso a regra é chamar sempre com o objeto na

frente, ou usar a forma explícita contador.somar(1). Note que nem o objeto

original é tocado: o total continua sendo o das chamadas feitas com o objeto

na frente.

Esse é o motivo de a função seta não servir como método: a seta não tem this

próprio, e o this dela é o do lugar onde foi escrita. Para método que precisa

de this, usa-se function.

A cadeia de chamadas liga o método ao próximo: lista.map(item => item.feita)

chama map no array e a seta em cada item.

Chamar método inexistente é TypeError: lista.naoExiste is not a function, e

ler propriedade de null ou undefined é

TypeError: Cannot read properties of undefined. São os dois erros que mais

aparecem no console do aluno, e os dois dizem exatamente onde olhar.

O this do exemplo está em quatro linhas que contam a história inteira.

metodo: ola, Ana mostra o método lendo this.nome e devolvendo o texto.

this no metodo: 5 | outra chamada: 8 mostra duas somas no mesmo objeto: 5 e

depois 8, porque o this.total += n somou ao valor que já estava lá. A linha

o total continua o das chamadas feitas com o objeto: 8 prova que as duas

chamadas mexeram no mesmo contador.

Entre elas está a linha que é o defeito: metodo sem objeto na frente: NaN. O

método foi guardado em const somar e chamado sozinho, então o this não era o

contador — e o total de onde ele foi procurar era undefined. undefined += 1

é NaN, e o console mostra NaN sem TypeError e sem aviso. É o

silêncio do modo frouxo de novo, e por isso o NaN na tela é quase sempre um

this perdido.

A linha seta como metodo: sem this é o outro lado: a seta não consultou o

relogio, que tinha horas: 10 ao lado. Ela devolveu o texto fixo, e é isso que

a diferencia de function quando as duas estão escritas como método.

Os dois erros do fim do exemplo saem em `metodo inexistente: TypeError -

[1,2].naoExiste is not a function e propriedade de null: TypeError - Cannot

read properties of null (reading 'nome')`. O primeiro diz qual método não

existe; o segundo diz qual propriedade foi lida e em qual objeto — e a parte

(reading 'nome') é a que aponta a linha exata.

O objeto aninhado do exemplo é o caminho até o dado:

aninhado: Bia | com atalho: 4. O primeiro é usuarioCompleto.filhas.nome; o

segundo é usuarioCompleto.filhas?.idade, com o atalho de opcional. A

diferença aparece quando filhas não existe: o ponto dá TypeError e o atalho

devolve undefined.

Exemplo

// Objeto: propriedades, metodos e o this. O exemplo mostra a diferenca
// entre notacao de ponto e de colchete, e os tres metodos que listam.
const usuario = {
  nome: 'Ana',
  idade: 30,
  ativo: true,
  saudar() {
    return `ola, ${this.nome}`;
  },
};

/* notacao de ponto e de colchete dao o mesmo resultado */
console.log('ponto:', usuario.nome, '| colchete:', usuario['nome']);

/* o colchete e necessario quando o nome vem de uma variavel */
const campo = 'idade';
console.log('colchete com variavel:', usuario[campo]);

/* propriedade ausente devolve undefined, nao e erro */
console.log('email:', usuario.email);
usuario.email = '[email protected]';   // cria a chave
console.log('depois de escrever:', usuario.email);

/* in pergunta pela chave; comparacao pergunta pelo valor */
const comIndefinido = { nome: 'Ana', apelido: undefined };
console.log("'apelido' in objeto:", 'apelido' in comIndefinido);
console.log('apelido !== undefined:', comIndefinido.apelido !== undefined);

/* delete remove a chave */
delete usuario.email;
console.log('depois do delete:', Object.keys(usuario));

/* os tres metodos que listam */
console.log('keys:', Object.keys(usuario));
console.log('values:', Object.values(usuario));
console.log('entries:', Object.entries(usuario));
console.log('entries com map:', Object.entries({ nome: 'Ana', idade: 30 })
  .map(([chave, valor]) => `${chave}: ${valor}`).join(' | '));

/* metodo e propriedade que guarda funcao; e o this que liga os dois */
console.log('metodo:', usuario.saudar());

const contador = {
  total: 0,
  somar(n) {
    this.total += n;
    return this.total;
  },
};
console.log('this no metodo:', contador.somar(5), '| outra chamada:', contador.somar(3));

/* funcao seta nao tem this proprio: nao serve como metodo */
const relogio = { horas: 10, descrever: () => 'sem this' };
console.log('seta como metodo:', relogio.descrever());

/* metodo guardado e chamado sem o objeto na frente: o this vira o objeto
   global em arquivo .js, e a conta sai errada sem erro nenhum */
const somar = contador.somar;
console.log('metodo sem objeto na frente:', somar(1));
console.log('o total continua o das chamadas feitas com o objeto:', contador.total);

/* os dois erros mais comuns no console do aluno */
try {
  [1, 2].naoExiste();
} catch (erro) {
  console.log('metodo inexistente:', erro.constructor.name, '-', erro.message);
}
try {
  const usuarioVazio = null;
  console.log(usuarioVazio.nome);
} catch (erro) {
  console.log('propriedade de null:', erro.constructor.name, '-', erro.message);
}

/* objeto aninhado: o caminho ate o dado */
const usuarioCompleto = { nome: 'Ana', filhas: { nome: 'Bia', idade: 4 } };
console.log('aninhado:', usuarioCompleto.filhas.nome, '| com atalho:', usuarioCompleto.filhas?.idade);

/* o objeto que vem da API */
const resposta = { dados: { tarefas: [{ id: 1, texto: 'estudar' }] }, erro: null };
console.log('da api:', resposta.dados.tarefas.length, 'tarefa | erro:', resposta.erro);

Saída real

ponto: Ana | colchete: Ana
colchete com variavel: 30
email: undefined
depois de escrever: [email protected]
'apelido' in objeto: true
apelido !== undefined: false
depois do delete: [ 'nome', 'idade', 'ativo', 'saudar' ]
keys: [ 'nome', 'idade', 'ativo', 'saudar' ]
values: [ 'Ana', 30, true, [Function: saudar] ]
entries: [
  [ 'nome', 'Ana' ],
  [ 'idade', 30 ],
  [ 'ativo', true ],
  [ 'saudar', [Function: saudar] ]
]
entries com map: nome: Ana | idade: 30
metodo: ola, Ana
this no metodo: 5 | outra chamada: 8
seta como metodo: sem this
metodo sem objeto na frente: NaN
o total continua o das chamadas feitas com o objeto: 8
metodo inexistente: TypeError - [1,2].naoExiste is not a function
propriedade de null: TypeError - Cannot read properties of null (reading 'nome')
aninhado: Bia | com atalho: 4
da api: 1 tarefa | erro: null
Aula 2

Desestruturação e spread

Desestruturação e spread

Desestruturação é escrever o nome de várias variáveis na mesma declaração,

colchete para frente do valor. Em objeto a forma é const seguido de { } — o

termo é const { }, sem nada entre a palavra e a chave. Em

array é o colchete comum. É a forma mais curta de pegar campos de objeto e de

pegar itens de array:

const usuario = { nome: 'Ana', idade: 30 };
const { nome, idade } = usuario;

Equivale a const nome = usuario.nome; const idade = usuario.idade;. O que faz

diferença é o uso: em React Native quase todo componente começa desestruturando,

porque o padrão são muitas props.

A propriedade renomeada usa : entre o nome original e o nome novo:

const { nome: apelido } = usuario;   // apelido vale 'Ana'

O nome depois do : é o nome da variável; o nome antes é o da propriedade.

O exemplo começa por dois campos: Ana 30, que é a linha do bloco acima: duas

variáveis nascidas de um objeto, e o console lê os dois nomes soltos. A linha do

nome trocado é renomeado: Ana — o valor é o mesmo, o nome da variável é outro.

E o valor padrão entra junto com a renomeação, numa linha só:

padrao: sem cidade | renomeado com padrao: 30. O objeto não tem cidade, e

o padrão entrou; o objeto tem idade, e o = 0 do padrão não foi usado porque

o valor existia. O = 0 apareceu depois do :, o que mostra que os dois

mecanismos se combinam na mesma declaração.

Desestruturar array

No array é por posição, e a ordem importa:

const tarefas = ['estudar', 'treinar'];
const [primeira, segunda] = tarefas;

O que falta vira undefined, e o valor padrão (=) cobre o buraco:

const [a, b = 'padrao'] = ['so um'];

Ignorar a primeira posição é poner espaço: const [, segundo] = tarefas.

As três linhas do exemplo resolvem posição, buraco e posição pulada.

array: estudar treinar são os dois primeiros itens da lista de três, na ordem.

array com buraco: so um padrao é o array de um item só: o primeiro veio, e o

segundo não existia, então o padrão entrou no lugar. `terceira posicao:

descansar pula duas posições com dois colchetes vazios, [, , terceiro]`.

Um detalhe do [, , terceiro]: as vírgulas dizem quantas posições pular, e cada

vírgula vazia é uma posição que não se quer. Não existe atalho para pegar o

último de um array por posição — para isso existe o .at(-1) da aula de arrays.

Desestruturar objeto aninhado

Duas vezes o colchete, na mesma linha:

const pessoa = { nome: 'Ana', filhas: { nome: 'Bia', idade: 4 } };
const { nome, filhas: { nome: filha, idade } } = pessoa;

A linha do exemplo é a mesma regra com nomes que não colidem:

{ nome: nomeDaPessoa, filhas: { nome: filha, idade: idadeDaFilha } }, e a

saída é aninhado: Ana Bia 4. A renomeação não é um detalhe aqui: sem ela,

o nome de fora e o nome de dentro seriam o mesmo nome, e o segundo

sobrescreveria o primeiro.

Quando a camada interna pode não existir, o operador opcional ?. evita o

TypeError: pessoa.filhas?.nome devolve undefined em vez de quebrar. E o

valor padrão junto (filhas = {}) resolve o caso de a chave não existir.

O exemplo usa o atalho num objeto que não tem filhas e imprime

com optional chaining: undefined | com padrao: Bia. A primeira parte é o objeto

sem a camada interna: o ?. short-circuitou e devolveu undefined, sem erro.

A segunda é o objeto com a camada, e o ?. deixou passar o nome.

É a diferença entre as duas defesas do parágrafo: o ?. protege a leitura de

uma camada que pode faltar, e o = {} protege a desestruturação quando o

parâmetro inteiro não chegou. O primeiro devolve undefined; o segundo evita o

TypeError da desestruturação.

Spread: espalhar as propriedades

O spread (...) copia as propriedades de um objeto num objeto novo, ou os

itens de um array num array novo:

const base = { nome: 'Ana' };
const completa = { ...base, idade: 30 };

A ordem importa: o que vem depois sobrescreve. { ...base, nome: 'Bia' } tem

'Bia'; { nome: 'Bia', ...base } tem 'Ana'. Por isso o spread entra no

começo quando o novo objeto é variação do antigo.

Em array, o spread achata um array dentro de outro:

const a = [1, 2];
const b = [...a, 3];    // [1, 2, 3]

Object.assign(alvo, fonte) faz o mesmo que o spread, e é a forma antiga:

Object.assign({}, base, { idade: 30 });

Copiar objeto sem Object.assign é o spread. A diferença que importa na

prática: Object.assign **mexe no primeiro

argumento**, e o spread cria objeto novo. Object.assign(base, { idade: 30 })

altera base.

A ordem do parágrafo sai numa linha do exemplo:

spread antes: Bia | spread depois: Ana. Com o ...base primeiro, o 'Bia'

escrito depois vence; com o 'Bia' primeiro e o ...base depois, o 'Ana' da

base vence. Nenhum dos dois objetos foi alterado — as duas expressões existem

só dentro do console.log.

O spread de objeto sai em `spread: { nome: 'Ana', idade: 30 } | base continua:

{ nome: 'Ana' }: o objeto novo tem as duas propriedades e a base` ficou só com

o nome. É a prova de que o spread copia.

E o Object.assign aparece nas duas formas na mesma seção:

assign em objeto novo: { nome: 'Ana', idade: 30 } e

assign no proprio objeto: { nome: 'Ana', idade: 30 }. As duas linhas parecem

iguais e não são: a primeira passou {} como alvo e o resultado foi num objeto

descartável; a segunda passou alvo e o alvo ficou com a idade. É o defeito

do assign que a linha do parágrafo descreve — e a razão de o spread ter

substituído a forma antiga.

O par entre chaves e ...: o resto

O ... com o nome do resto é o mesmo operador no outro sentido: junta o que

sobrou num objeto ou array novo.

const { nome, ...resto } = usuario;
// nome vale 'Ana', resto tem o resto das propriedades
const [primeiro, ...outros] = [1, 2, 3];
// primeiro vale 1, outros vale [2, 3]

É a forma de um componente aceitar quase tudo, repassar quase tudo, e mexer só em

um campo:

function Botao({ texto, ...outrasProps }) {
  return <Pressable {...outrasProps}><Text>{texto}</Text></Pressable>;
}

As duas linhas do exemplo são rest em objeto: { idade: 30, ativo: true } e

rest em array: [ 'treinar', 'descansar' ]. O objeto tinha nome, idade e

ativo, e o resto ficou com os dois últimos; o array tinha três textos, e o

outros ficou com os dois últimos. O que foi nomeado sai da lista, e o resto

fica inteiro.

O uso real do rest sai em

repasse: {"texto":"Salvar","repassadas":["onPress","testID"]}. A função pegou

texto e deixou o resto; o resultado tem texto à parte e o Object.keys do

resto mostra o que sobrou. É exatamente o que o Botao do bloco acima faz com

outrasProps: uma prop usada por conta própria, todas as outras repassadas sem

nomes.

Cuidado: desestruturar perde o original

const { nome } = usuario não apaga nada — usuario.nome continua lá. Mas

desestruturar de um parâmetro que chega undefined quebra na hora, e o erro sai

antes da tela:

function mostrar({ nome }) { return nome; }
mostrar(undefined);   // TypeError

A linha do exemplo é `desestruturar undefined: TypeError - Cannot destructure

property 'nome' of 'undefined' as it is undefined.` A mensagem diz as três

coisas que importam: que a desestruturação falhou, qual propriedade foi pedida, e

que o valor de origem era undefined.

O conserto é a linha seguinte, e são duas formas na mesma linha:

com padrao duplo: visitante | com valor: Ana. A função tem

= {} no parâmetro e = 'visitante' na propriedade — o padrão do objeto

protege a desestruturação, e o padrão da propriedade protege a leitura. Chamada

sem argumento, devolveu 'visitante'; chamada com o nome, devolveu 'Ana'.

É a diferença entre as duas defesas do parágrafo, e vale escolher por ordem: o

= {} vem depois da desestruturação das chaves, porque é o que impede a

desestruturação de rodar em cima de undefined.

Exemplo

// Destruturacao e spread: pegar campos, renomear, achatar e repassar.
const usuario = { nome: 'Ana', idade: 30, ativo: true };
const pessoa = { nome: 'Ana', filhas: { nome: 'Bia', idade: 4 } };
const tarefas = ['estudar', 'treinar', 'descansar'];

/* destructuring de objeto: o nome das variaveis vem da chave */
const { nome, idade } = usuario;
console.log('dois campos:', nome, idade);

/* renomeando: o nome depois dos dois pontos e o da variavel */
const { nome: apelido } = usuario;
console.log('renomeado:', apelido);

/* valor padrao cobre o buraco */
const { cidade = 'sem cidade', idade: anos = 0 } = usuario;
console.log('padrao:', cidade, '| renomeado com padrao:', anos);

/* destructuring de array: por posicao */
const [primeira, segunda] = tarefas;
console.log('array:', primeira, segunda);

/* o que falta vira undefined; o padrao cobre */
const [um, dois = 'padrao'] = ['so um'];
console.log('array com buraco:', um, dois);

/* ignorar a primeira posicao */
const [, , terceiro] = tarefas;
console.log('terceira posicao:', terceiro);

/* objeto aninhado em duas linhas de colchete */
const { nome: nomeDaPessoa, filhas: { nome: filha, idade: idadeDaFilha } } = pessoa;
console.log('aninhado:', nomeDaPessoa, filha, idadeDaFilha);

/* ?. e o padrao quando a camada interna nao existe */
const semFilhas = { nome: 'Bruno' };
console.log('com optional chaining:', semFilhas.filhas?.nome, '| com padrao:', pessoa.filhas?.nome);

/* spread de objeto: cria um objeto novo, e o original fica como estava */
const base = { nome: 'Ana' };
const completa = { ...base, idade: 30 };
console.log('spread:', completa, '| base continua:', base);

/* a ordem decide quem vence */
console.log('spread antes:', { ...base, nome: 'Bia' }.nome, '| spread depois:', { nome: 'Bia', ...base }.nome);

/* spread de array: achata */
const a = [1, 2];
console.log('achata:', [...a, 3], '| dentro de outro:', [...a, ...[4, 5]]);

/* Object.assign faz o mesmo, mas mexe no primeiro argumento */
console.log('assign em objeto novo:', Object.assign({}, base, { idade: 30 }));
const alvo = { nome: 'Ana' };
Object.assign(alvo, { idade: 30 });
console.log('assign no proprio objeto:', alvo);

/* rest: o que sobra */
const { nome: primeiroNome, ...resto } = usuario;
console.log('rest em objeto:', resto);
const [primeiro, ...outros] = tarefas;
console.log('rest em array:', outros);

/* o componente que repassa quase tudo: o uso real do rest */
function resumoDe(props) {
  const { texto, ...outras } = props;
  return { texto, repassadas: Object.keys(outras) };
}
console.log('repasse:', JSON.stringify(resumoDe({ texto: 'Salvar', onPress: () => {}, testID: 'botao' })));

/* desestruturar de quem chegou undefined quebra na hora */
try {
  (function ({ nome }) { return nome; })(undefined);
} catch (erro) {
  console.error(erro.constructor.name + ': ' + erro.message);
  console.log('desestruturar undefined:', erro.constructor.name, '-', erro.message);
}

/* o padrao resolve o mesmo caso */
function comPadrao({ nome = 'visitante' } = {}) { return nome; }
console.log('com padrao duplo:', comPadrao(), '| com valor:', comPadrao({ nome: 'Ana' }));

Saída real

dois campos: Ana 30
renomeado: Ana
padrao: sem cidade | renomeado com padrao: 30
array: estudar treinar
array com buraco: so um padrao
terceira posicao: descansar
aninhado: Ana Bia 4
com optional chaining: undefined | com padrao: Bia
spread: { nome: 'Ana', idade: 30 } | base continua: { nome: 'Ana' }
spread antes: Bia | spread depois: Ana
achata: [ 1, 2, 3 ] | dentro de outro: [ 1, 2, 4, 5 ]
assign em objeto novo: { nome: 'Ana', idade: 30 }
assign no proprio objeto: { nome: 'Ana', idade: 30 }
rest em objeto: { idade: 30, ativo: true }
rest em array: [ 'treinar', 'descansar' ]
repasse: {"texto":"Salvar","repassadas":["onPress","testID"]}
desestruturar undefined: TypeError - Cannot destructure property 'nome' of 'undefined' as it is undefined.
com padrao duplo: visitante | com valor: Ana