📜 JavaScript & JSON
💡 Origem do JSON
JSON é um subconjunto da sintaxe de objetos JavaScript. Por isso, trabalhar com JSON em JavaScript é muito simples e natural.
Visão Geral
| Método | Descrição | Direção |
|---|---|---|
JSON.parse() |
Converte string JSON em objeto JS | JSON → JavaScript |
JSON.stringify() |
Converte objeto JS em string JSON | JavaScript → JSON |
📥 JSON.parse()
Converte uma string JSON num objeto JavaScript.
Sintaxe
Sintaxe
const objeto = JSON.parse(textoJSON[, reviver]);
Exemplo Básico
Parse Simples
// String JSON recebida de API, ficheiro, etc.
const jsonString = '{"nome":"Ana","idade":25,"ativo":true}';
// Converter para objeto JavaScript
const pessoa = JSON.parse(jsonString);
// Agora podes aceder como objeto normal
console.log(pessoa.nome); // "Ana"
console.log(pessoa.idade); // 25
console.log(pessoa.ativo); // true
Parse de Arrays
Array JSON
const jsonArr = '[1, 2, 3, 4, 5]';
const numeros = JSON.parse(jsonArr);
console.log(numeros[0]); // 1
console.log(numeros.length); // 5
// Array de objetos
const jsonUsers = '[{"id":1,"nome":"Ana"},{"id":2,"nome":"Bruno"}]';
const users = JSON.parse(jsonUsers);
users.forEach(user => {
console.log(user.nome);
});
// "Ana"
// "Bruno"
Reviver Function
A função reviver permite transformar valores durante o parse:
Reviver Function
const json = '{"nome":"Ana","nascimento":"1995-03-15"}';
const pessoa = JSON.parse(json, (key, value) => {
// Se a chave for "nascimento", converter para Date
if (key === 'nascimento') {
return new Date(value);
}
return value;
});
console.log(pessoa.nascimento); // Date object
console.log(pessoa.nascimento.getFullYear()); // 1995
📤 JSON.stringify()
Converte um valor JavaScript numa string JSON.
Sintaxe
Sintaxe
const json = JSON.stringify(valor[, replacer[, space]]);
Exemplo Básico
Stringify Simples
const pessoa = {
nome: "Ana",
idade: 25,
ativo: true
};
const json = JSON.stringify(pessoa);
console.log(json);
// '{"nome":"Ana","idade":25,"ativo":true}'
Formatação Legível
Indentação
const pessoa = {
nome: "Ana",
idade: 25,
endereco: {
cidade: "Lisboa",
pais: "Portugal"
}
};
// Com indentação (2 espaços)
const json = JSON.stringify(pessoa, null, 2);
console.log(json);
/*
{
"nome": "Ana",
"idade": 25,
"endereco": {
"cidade": "Lisboa",
"pais": "Portugal"
}
}
*/
Filtrar Propriedades
Replacer Array
const pessoa = {
nome: "Ana",
idade: 25,
senha: "123456", // Não queremos incluir!
email: "ana@exemplo.com"
};
// Apenas incluir certas propriedades
const json = JSON.stringify(pessoa, ['nome', 'email']);
console.log(json);
// '{"nome":"Ana","email":"ana@exemplo.com"}'
Replacer Function
Replacer Function
const pessoa = {
nome: "Ana",
senha: "123456",
token: "abc123"
};
const json = JSON.stringify(pessoa, (key, value) => {
// Remover campos sensíveis
if (key === 'senha' || key === 'token') {
return undefined; // Não incluir no JSON
}
return value;
});
console.log(json);
// '{"nome":"Ana"}'
toJSON Method
Personalizar Serialização
class Utilizador {
constructor(nome, email) {
this.nome = nome;
this.email = email;
this.senha = 'secreta'; // Não incluir no JSON
this.criadoEm = new Date();
}
// Método especial para JSON
toJSON() {
return {
nome: this.nome,
email: this.email
// senha e criadoEm omitidos
};
}
}
const user = new Utilizador('Ana', 'ana@exemplo.com');
console.log(JSON.stringify(user));
// '{"nome":"Ana","email":"ana@exemplo.com"}'
🌐 Fetch API e JSON
A Fetch API é a forma moderna de fazer pedidos HTTP em JavaScript.
Pedido GET
Fetch GET
// Buscar dados de uma API
fetch('https://jsonplaceholder.typicode.com/users/1')
.then(response => {
// Verificar se o pedido foi bem-sucedido
if (!response.ok) {
throw new Error('Erro na rede');
}
return response.json(); // Parse do JSON
})
.then(user => {
console.log(user.name);
console.log(user.email);
})
.catch(error => {
console.error('Erro:', error);
});
Async/Await
Async/Await
async function buscarUtilizador(id) {
try {
const response = await fetch(
`https://jsonplaceholder.typicode.com/users/${id}`
);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const user = await response.json();
return user;
} catch (error) {
console.error('Erro ao buscar:', error);
throw error;
}
}
// Uso
const user = await buscarUtilizador(1);
console.log(user.name);
Pedido POST
Fetch POST
async function criarPost(post) {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(post)
}
);
if (!response.ok) {
throw new Error('Erro ao criar post');
}
return await response.json();
}
// Uso
const novoPost = await criarPost({
title: 'Meu Post',
body: 'Conteúdo do post',
userId: 1
});
console.log('Post criado com ID:', novoPost.id);
Tratamento de Erros Completo
Fetch com Tratamento Robusto
async function fetchComTratamento(url) {
try {
const response = await fetch(url);
// Verificar status HTTP
if (!response.ok) {
if (response.status === 404) {
throw new Error('Recurso não encontrado');
} else if (response.status === 500) {
throw new Error('Erro no servidor');
}
throw new Error(`HTTP ${response.status}`);
}
// Verificar Content-Type
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new Error('Resposta não é JSON');
}
return await response.json();
} catch (error) {
if (error instanceof TypeError) {
// Erro de rede (sem conexão, DNS, etc.)
console.error('Erro de rede:', error.message);
} else {
console.error('Erro:', error.message);
}
throw error;
}
}
💾 LocalStorage
LocalStorage só guarda strings. Usa JSON para guardar objetos.
Guardar Objeto
Guardar em LocalStorage
// Guardar objeto
const config = {
tema: 'escuro',
idioma: 'pt',
notificacoes: true
};
// Converter para JSON e guardar
localStorage.setItem('config', JSON.stringify(config));
Recuperar Objeto
Ler de LocalStorage
// Ler e converter de volta para objeto
const json = localStorage.getItem('config');
if (json) {
const config = JSON.parse(json);
console.log(config.tema); // 'escuro'
} else {
console.log('Config não encontrada');
}
Funções Utilitárias
Utilitários LocalStorage
// Guardar objeto
function guardar(chave, valor) {
localStorage.setItem(chave, JSON.stringify(valor));
}
// Ler objeto
function ler(chave, valorPadrao = null) {
const json = localStorage.getItem(chave);
if (!json) return valorPadrao;
try {
return JSON.parse(json);
} catch (e) {
console.error('JSON inválido no localStorage:', e);
return valorPadrao;
}
}
// Remover
function remover(chave) {
localStorage.removeItem(chave);
}
// Exemplo de uso
guardar('utilizador', { nome: 'Ana', id: 1 });
const user = ler('utilizador', {}); // {} se não existir
console.log(user.nome); // 'Ana'
Lista de Tarefas com LocalStorage
Exemplo Prático
class ListaTarefas {
constructor() {
this.tarefas = this.carregar();
}
carregar() {
const json = localStorage.getItem('tarefas');
return json ? JSON.parse(json) : [];
}
guardar() {
localStorage.setItem('tarefas', JSON.stringify(this.tarefas));
}
adicionar(texto) {
const tarefa = {
id: Date.now(),
texto: texto,
feita: false,
criadaEm: new Date().toISOString()
};
this.tarefas.push(tarefa);
this.guardar();
return tarefa;
}
marcarFeita(id) {
const tarefa = this.tarefas.find(t => t.id === id);
if (tarefa) {
tarefa.feita = true;
this.guardar();
}
}
remover(id) {
this.tarefas = this.tarefas.filter(t => t.id !== id);
this.guardar();
}
listar() {
return this.tarefas;
}
}
// Uso
const lista = new ListaTarefas();
lista.adicionar('Aprender JSON');
lista.adicionar('Praticar JavaScript');
console.log(lista.listar());
🚨 Tratamento de Erros
Try/Catch
Try/Catch com JSON
function parseSeguro(jsonString) {
try {
const data = JSON.parse(jsonString);
return { sucesso: true, data: data };
} catch (error) {
return {
sucesso: false,
erro: error.message,
data: null
};
}
}
// Uso
const resultado = parseSeguro('{"nome":"Ana"}');
if (resultado.sucesso) {
console.log(resultado.data.nome);
} else {
console.log('JSON inválido:', resultado.erro);
}
Erros Comuns
| Erro | Causa | Solução |
|---|---|---|
SyntaxError |
JSON mal formatado | Validar JSON antes de parse |
TypeError |
Valor não é string | Verificar tipo antes de parse |
undefined |
Propriedade não existe | Verificar com ?. ou hasOwnProperty |
Validação
Validar JSON
function isValidJson(str) {
try {
JSON.parse(str);
return true;
} catch (e) {
return false;
}
}
// Uso
console.log(isValidJson('{"nome":"Ana"}')); // true
console.log(isValidJson('{nome:"Ana"}')); // false
console.log(isValidJson('not json')); // false
Acesso Seguro
Optional Chaining
const json = '{"empresa":{"endereco":{"cidade":"Lisboa"}}}';
const data = JSON.parse(json);
// Perigoso - pode lançar erro
// const cidade = data.empresa.endereco.cidade;
// Seguro com optional chaining
const cidade = data?.empresa?.endereco?.cidade ?? 'Desconhecida';
// Ou com verificação
if (data.empresa && data.empresa.endereco) {
console.log(data.empresa.endereco.cidade);
}
💡 Exemplos Práticos
Deep Clone
Clone Profundo
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
const original = {
nome: 'Ana',
endereco: { cidade: 'Lisboa' }
};
const copia = deepClone(original);
// Modificar cópia não afeta original
copia.endereco.cidade = 'Porto';
console.log(original.endereco.cidade); // 'Lisboa' (inalterado)
Comparar Objetos
Comparar JSON
function objetosIguais(obj1, obj2) {
return JSON.stringify(obj1) === JSON.stringify(obj2);
}
const a = { x: 1, y: 2 };
const b = { x: 1, y: 2 };
const c = { y: 2, x: 1 }; // Ordem diferente
console.log(objetosIguais(a, b)); // true
console.log(objetosIguais(a, c)); // false (ordem importa!)
Debug
Debug com JSON
// Mostrar objeto de forma legível
function debug(obj, titulo = 'Debug') {
console.log('=== ' + titulo + ' ===');
console.log(JSON.stringify(obj, null, 2));
}
const dados = { users: [{ id: 1, nome: 'Ana' }] };
debug(dados, 'Utilizadores');
📝 Exercícios
Exercício 1: Parse
Problema: Converte esta string JSON num objeto e mostra o nome da primeira pessoa:
[{"id":1,"nome":"Ana","idade":25},{"id":2,"nome":"Bruno","idade":30}]
const json = '[{"id":1,"nome":"Ana","idade":25},{"id":2,"nome":"Bruno","idade":30}]';
const pessoas = JSON.parse(json);
console.log(pessoas[0].nome); // "Ana"
Exercício 2: Stringify Formatado
Problema: Converte este objeto para JSON formatado com 2 espaços de indentação:
const config = { tema: 'escuro', idioma: 'pt' };
const config = { tema: 'escuro', idioma: 'pt' };
const json = JSON.stringify(config, null, 2);
console.log(json);
/*
{
"tema": "escuro",
"idioma": "pt"
}
*/
Exercício 3: Fetch API
Problema: Cria uma função async que busca um utilizador da API JSONPlaceholder e retorna o nome.
async function buscarNomeUtilizador(id) {
const response = await fetch(
`https://jsonplaceholder.typicode.com/users/${id}`
);
const user = await response.json();
return user.name;
}
// Uso
const nome = await buscarNomeUtilizador(1);
console.log(nome); // "Leanne Graham"