Engenharia de IA Aplicada à Programação Web
Aula 5 de 8
Navegar por módulos e aulas
  1. 01 Fundamentos da Web
  2. 02 JavaScript moderno
  3. 03 TypeScript, Git e qualidade
  4. 04 Angular
  5. 05 Node.js, NestJS e APIs
  1. 2.1 Valores, variáveis e tipos
  2. 2.2 Condições e repetições
  3. 2.3 Funções, escopo e closures
  4. 2.4 Arrays e transformação de dados
  5. 2.5 Objetos, JSON e modelagem
  6. 2.6 Módulos e tratamento de erros
  7. 2.7 Promises, async/await e Fetch
  8. 2.8 Armazenamento, testes e projeto

Módulo 2 · Aula 2.5

Objetos, JSON e modelagem

2 horas Teoria + laboratório JavaScript moderno
Ver fonte Markdown

Identificação

  • Duração: 2 horas
  • Tipo: teoria aplicada e laboratório
  • Entrega: modelo de tarefa com importação e exportação JSON
  • Laboratório: ../exemplos/aula-2.5/index.html

Introdução

O que é um objeto?

Um objeto JavaScript reúne informações relacionadas por meio de propriedades:

const task = {
  id: 1,
  title: "Estudar objetos",
  status: "doing",
  estimate: 3,
};

Cada propriedade possui uma chave e um valor. Objetos são úteis para representar entidades, configurações e resultados com campos nomeados.

Objeto e array são a mesma coisa?

Não. Um objeto representa normalmente uma entidade:

const task = {
  title: "Estudar",
  status: "todo",
};

Um array representa uma coleção ordenada:

const tasks = [
  { title: "Estudar", status: "todo" },
  { title: "Praticar", status: "doing" },
];

É comum utilizar arrays de objetos porque temos várias entidades com o mesmo formato.

Objeto e classe são a mesma coisa?

Não. Um objeto é um valor concreto. Uma classe é uma forma de definir como objetos podem ser construídos e quais comportamentos compartilham.

JavaScript permite criar objetos diretamente, sem classe:

const settings = {
  theme: "dark",
};

Neste curso, começaremos com objetos literais e funções. Classes serão usadas apenas quando trouxerem uma vantagem clara.

O que é JSON?

JSON significa JavaScript Object Notation. É um formato textual usado para trocar dados:

{
  "title": "Estudar objetos",
  "status": "doing",
  "estimate": 3
}

JSON se parece com um objeto JavaScript, mas não é a mesma coisa:

  • objeto JavaScript é um valor em memória;
  • JSON é texto;
  • JSON exige chaves entre aspas duplas;
  • JSON não transporta funções;
  • comentários e vírgulas finais não são permitidos no JSON padrão.

JSON é um banco de dados?

Não. JSON é um formato. Ele pode ser enviado por uma API, armazenado em arquivo ou guardado em uma coluna, mas não oferece sozinho consultas, relacionamentos, transações e controle de acesso.

No projeto futuro, o navegador trocará JSON com a API, e a API persistirá os dados no MySQL.

Onde isso aparece no projeto?

Nesta aula, modelaremos uma tarefa com campos consistentes, criaremos cópias sem alterar o objeto original e converteremos o modelo entre objeto e JSON. Dados importados serão validados antes de entrar na aplicação.

Objetivos

Ao final da aula, o aluno deverá conseguir:

  1. criar e acessar objetos;
  2. diferenciar objeto, array, classe, JSON e banco de dados;
  3. adicionar, atualizar e remover propriedades;
  4. compreender referências de objetos;
  5. copiar objetos com spread;
  6. reconhecer os limites de uma cópia rasa;
  7. utilizar desestruturação e valores padrão;
  8. aplicar optional chaining e nullish coalescing;
  9. modelar uma entidade com campos coerentes;
  10. serializar e interpretar JSON;
  11. validar dados externos antes do uso.

Pré-requisitos

  • Aulas 2.1 a 2.4 concluídas;
  • valores, tipos, funções e arrays;
  • noções de formulário e DOM;
  • navegador, DevTools e editor.

Pergunta orientadora

Como representar uma entidade de forma consistente e trocar seus dados sem confundir objeto em memória com texto JSON?

Roteiro sugerido

Etapa Duração
Objetos e propriedades 25 min
Referência, cópia e desestruturação 30 min
Modelagem de entidades 20 min
JSON e validação 25 min
Laboratório 15 min
Revisão 5 min

1. Objeto literal

const student = {
  name: "Ana",
  active: true,
  completedLessons: 4,
};

As chaves podem ser escritas sem aspas quando são identificadores válidos. Valores podem ser strings, números, booleanos, arrays, outros objetos, funções ou valores ausentes.

2. Acesso com ponto

student.name;
student.active;

A notação de ponto é a opção mais clara quando conhecemos o nome da propriedade.

3. Acesso com colchetes

student["name"];

Colchetes são necessários quando:

  • o nome contém caracteres incompatíveis com a notação de ponto;
  • a chave está guardada em uma variável;
  • a propriedade é calculada dinamicamente.
const selectedField = "completedLessons";
student[selectedField];

Não use:

student.selectedField;

Isso procura literalmente uma propriedade chamada selectedField.

4. Criar e atualizar propriedades

const task = {
  title: "Estudar",
};

task.status = "todo";
task.title = "Estudar objetos";

Mesmo declarado com const, o conteúdo do objeto pode mudar. const impede que a variável passe a apontar para outro objeto:

task = {}; // TypeError

5. Remover propriedades

delete task.temporaryField;

Antes de remover, avalie se o campo deveria ser opcional ou receber null. Estruturas consistentes são mais fáceis de validar e exibir.

6. Propriedades calculadas

const fieldName = "priority";

const task = {
  title: "Estudar",
  [fieldName]: "high",
};

O valor de fieldName se torna a chave.

7. Atalhos de propriedade

Quando variável e chave têm o mesmo nome:

const title = "Estudar objetos";
const status = "doing";

const task = {
  title,
  status,
};

Equivale a:

const task = {
  title: title,
  status: status,
};

8. Métodos

Uma função armazenada em uma propriedade é um método:

const task = {
  title: "Estudar",
  describe() {
    return `Tarefa: ${this.title}`;
  },
};

this depende da forma como a função é chamada. Regras puras que recebem dados por parâmetro costumam ser mais simples de reutilizar:

function describeTask(task) {
  return `Tarefa: ${task.title}`;
}

9. Objetos são acessados por referência

const original = {
  title: "Estudar",
};

const alias = original;
alias.title = "Alterado";

console.log(original.title); // "Alterado"

alias e original apontam para o mesmo objeto.

Comparações também usam referência:

{} === {}; // false

const task = {};
task === task; // true

Dois objetos com campos iguais não são automaticamente a mesma referência.

10. Cópia com spread

const original = {
  title: "Estudar",
  status: "todo",
};

const updated = {
  ...original,
  status: "done",
};

updated é um novo objeto. original.status continua sendo "todo".

A ordem importa:

const wrongOrder = {
  status: "done",
  ...original,
};

O status do original sobrescreve "done".

11. Cópia rasa

Spread copia apenas o primeiro nível:

const original = {
  title: "Estudar",
  metadata: {
    source: "course",
  },
};

const copy = { ...original };
copy.metadata.source = "manual";

console.log(original.metadata.source); // "manual"

Para atualizar de maneira imutável:

const updated = {
  ...original,
  metadata: {
    ...original.metadata,
    source: "manual",
  },
};

12. structuredClone

Para dados compatíveis, o navegador oferece cópia profunda:

const copy = structuredClone(original);

structuredClone suporta vários tipos, mas não copia funções e pode falhar com valores não clonáveis. Não utilize JSON.stringify seguido de JSON.parse como solução geral de cópia profunda, pois tipos e valores podem ser perdidos.

13. Desestruturação

Extrai propriedades para variáveis:

const task = {
  title: "Estudar",
  status: "doing",
};

const { title, status } = task;

Renomeando:

const { title: taskTitle } = task;

Valor padrão:

const { estimate = 1 } = task;

O padrão é usado quando a propriedade é undefined, não quando é null.

14. Rest em objetos

const task = {
  id: 1,
  title: "Estudar",
  status: "doing",
};

const { id, ...editableFields } = task;

editableFields recebe uma cópia rasa das demais propriedades.

15. Optional chaining

const city = user.address?.city;

Se address for null ou undefined, o resultado será undefined em vez de um erro.

Não use optional chaining para esconder um campo obrigatório ausente. Ele é útil quando a ausência é realmente permitida.

16. Nullish coalescing

const estimate = task.estimate ?? 1;

O valor padrão é usado apenas para null ou undefined.

Compare:

const valueWithOr = task.estimate || 1;

Se estimate for 0, || escolherá 1, enquanto ?? preservará 0.

17. Verificar propriedades

Object.hasOwn(task, "title");

Isso verifica se a propriedade pertence diretamente ao objeto.

Para listar:

Object.keys(task);
Object.values(task);
Object.entries(task);

Object.entries produz pares [chave, valor], úteis em iteração.

18. Modelagem de uma tarefa

Antes de programar, defina o significado dos campos:

const task = {
  id: "task-001",
  title: "Estudar objetos",
  description: "",
  status: "todo",
  priority: "planned",
  estimateHours: 2,
  tags: ["javascript", "curso"],
  completedAt: null,
};

Decisões:

  • id identifica a entidade;
  • title é obrigatório;
  • description pode ser string vazia;
  • status aceita alternativas conhecidas;
  • estimateHours é número não negativo;
  • tags é um array de strings;
  • completedAt usa null enquanto não concluída.

Um bom modelo reduz estados ambíguos.

19. Fábrica de objetos

function createTask(input) {
  const title = input.title.trim();

  return {
    id: crypto.randomUUID(),
    title,
    description: input.description?.trim() ?? "",
    status: input.status ?? "todo",
    priority: input.priority ?? "planned",
    estimateHours: Number(input.estimateHours ?? 0),
    tags: input.tags ?? [],
    completedAt: null,
  };
}

A fábrica centraliza padrões e normalização. Isso não substitui validação.

20. Objeto JavaScript para JSON

const jsonText = JSON.stringify(task);

Formatado para leitura:

const jsonText = JSON.stringify(task, null, 2);

O terceiro argumento define a indentação.

Valores como undefined, funções e símbolos não são representados normalmente em objetos JSON. Datas viram strings.

21. JSON para valor JavaScript

const parsed = JSON.parse(jsonText);

JSON.parse pode lançar SyntaxError:

try {
  const parsed = JSON.parse(jsonText);
} catch (error) {
  console.error("JSON inválido", error);
}

O resultado não deve ser confiado apenas porque o texto é JSON válido.

22. Sintaxe válida não garante modelo válido

Este JSON é sintaticamente válido:

{
  "title": 42,
  "status": "qualquer-coisa"
}

Mas não respeita nosso modelo. Precisamos validar:

function validateTask(value) {
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
    return false;
  }

  const hasValidTitle =
    typeof value.title === "string" &&
    value.title.trim().length >= 3;

  const allowedStatuses = ["todo", "doing", "done"];
  const hasValidStatus = allowedStatuses.includes(value.status);

  return hasValidTitle && hasValidStatus;
}

Em módulos posteriores, usaremos bibliotecas e contratos TypeScript para tornar essa validação mais robusta.

23. JSON não executa código

JSON deve ser interpretado com JSON.parse, nunca com eval:

const value = JSON.parse(jsonText);

Não use:

const value = eval(`(${jsonText})`);

eval pode executar conteúdo malicioso e não é necessário para ler JSON.

24. Datas no JSON

const task = {
  createdAt: new Date(),
};

const text = JSON.stringify(task);

A data se torna string ISO. Ao interpretar:

const parsed = JSON.parse(text);
typeof parsed.createdAt; // "string"

Se a aplicação precisa de Date, converta explicitamente após validar o formato.

25. Laboratório guiado

Abra o modelador de tarefas.

Etapa 1 — Crie o objeto

Preencha o formulário e clique em Criar modelo. Observe:

  • normalização do título;
  • conversão da estimativa;
  • transformação das tags em array;
  • campos padrão;
  • JSON formatado.

Etapa 2 — Atualize sem mutar

Marque a tarefa como concluída. O laboratório cria um novo objeto com spread e preserva a versão anterior.

Etapa 3 — Importe JSON

Edite o JSON e clique em Validar e importar. Teste:

  1. JSON válido e modelo válido;
  2. erro de sintaxe;
  3. título numérico;
  4. status não permitido;
  5. objeto ausente ou array no lugar da tarefa.

Etapa 4 — Inspecione o código

Localize:

  • createTask;
  • completeTask;
  • serializeTask;
  • parseAndValidateTask;
  • validateTask;
  • atualizações com spread.

26. Erros comuns

Confundir referência com cópia

const copy = original;

Isso cria um alias. Para copiar o primeiro nível:

const copy = { ...original };

Confiar em JSON externo

JSON.parse verifica sintaxe, não regras de negócio. Sempre valide estrutura e tipos.

Esquecer que JSON é texto

jsonText.title; // undefined

Primeiro:

const task = JSON.parse(jsonText);
task.title;

Usar || quando zero é válido

const estimate = input.estimate || 1;

Use ?? quando apenas ausência deve acionar o padrão.

Espalhar dados não confiáveis sem filtrar

const task = {
  ...externalValue,
};

Selecione e valide os campos permitidos. Não transporte propriedades arbitrárias para entidades internas.

27. Boas práticas

  • modele campos antes de construir a interface;
  • use nomes consistentes;
  • diferencie ausência, vazio e zero;
  • preserve identificadores em atualizações;
  • copie cada nível que será alterado;
  • valide todo dado externo;
  • trate erros de JSON.parse;
  • use JSON.stringify para serializar;
  • nunca utilize eval para JSON;
  • não inclua segredos em JSON enviado ao navegador.

28. Exercícios

Exercício 1 — Perfil

Crie um objeto student com nome, e-mail e aulas concluídas.

Exercício 2 — Atualização

Crie uma nova versão de uma tarefa com status: "done" sem alterar a original.

Exercício 3 — Desestruturação

Extraia title e status, renomeando title para taskTitle.

Exercício 4 — Modelo aninhado

Atualize metadata.source copiando corretamente os dois níveis.

Exercício 5 — JSON

Serialise um objeto, interprete o texto e valide os campos obrigatórios.

29. Desafio

Amplie o laboratório:

  • permita importar um array de tarefas;
  • valide cada item e informe o índice do erro;
  • rejeite propriedades desconhecidas;
  • adicione createdAt em formato ISO;
  • converta a data validada para Date apenas na camada de aplicação;
  • exporte somente campos públicos.

30. Lista de verificação de conclusão

  • Sei diferenciar objeto, array, JSON e banco de dados.
  • Consigo usar ponto e colchetes.
  • Entendo que objetos usam referências.
  • Sei criar uma atualização com spread.
  • Consigo explicar cópia rasa.
  • Uso desestruturação e valores padrão.
  • Sei diferenciar ?? e ||.
  • Converto objeto para JSON e JSON para objeto.
  • Valido dados depois de JSON.parse.
  • Não utilizo eval.

31. Critérios de avaliação

Critério Pontos
Modelo coerente e documentado 25
Atualizações sem mutação indevida 20
Serialização e interpretação JSON 20
Validação de dados externos 25
Interface e mensagens de erro 10
Total 100

Resumo

Nesta aula, aprendemos que:

  • objetos representam dados por propriedades nomeadas;
  • arrays representam coleções ordenadas;
  • objetos são acessados por referência;
  • spread cria uma cópia rasa;
  • desestruturação facilita acessar campos;
  • JSON é texto, não objeto e não banco de dados;
  • JSON.parse verifica sintaxe, mas a aplicação ainda precisa validar o modelo.

Próxima aula

Na Aula 2.6, separaremos o código em módulos com import e export e trataremos falhas previsíveis com erros, exceções e estados de recuperação.