A classe `JSON` em JavaScript
Este artigo explica a classe JSON em JavaScript.
Vamos explicar a classe JSON em JavaScript com exemplos práticos.
YouTube Video
A classe JSON em JavaScript
O objeto JSON possui principalmente dois métodos. JSON.stringify() converte um objeto em uma string JSON, e JSON.parse() cria um objeto a partir de uma string JSON. JSON é um formato de troca de dados que pode expressar apenas alguns valores do JavaScript. Funções, undefined, Symbol e referências circulares não podem ser convertidos diretamente para JSON.
JSON.stringify()
Primeiramente, aqui está um exemplo básico de como converter um objeto para uma string JSON.
1// Convert a JavaScript object to a JSON string.
2const obj = { name: "Alice", age: 30, active: true };
3const jsonString = JSON.stringify(obj);
4console.log(jsonString); // {"name":"Alice","age":30,"active":true}
- Este código é o exemplo mais básico de conversão de um objeto comum em uma string JSON.
JSON.stringifyretorna a string de forma síncrona.
O segundo argumento do JSON.stringify (replacer)
Ao especificar o replacer, o segundo argumento do JSON.stringify, você pode controlar detalhadamente as regras de conversão. Aqui está um exemplo usando um array para manter apenas propriedades específicas.
1// Use a replacer array to include only specific properties during stringification.
2const user = { id: 1, name: "Bob", password: "secret", role: "admin" };
3const safeJson = JSON.stringify(user, ["id", "name", "role"]);
4console.log(safeJson); // {"id":1,"name":"Bob","role":"admin"}
- Neste exemplo,
passwordé excluído para que a saída do log seja segura. Isso é útil quando você deseja remover informações sensíveis por motivos de segurança.
Usando replacer como uma função (para conversão e filtragem de valores)
Se você quiser mais flexibilidade, pode fornecer uma função para processar cada chave e valor. Abaixo está um exemplo de como manter um Date como uma string ISO.
1// Use a replacer function to customize serialization.
2const data = { name: "Carol", joined: new Date("2020-01-01T12:00:00Z") };
3const jsonCustom = JSON.stringify(data, (key, value) => {
4 // Convert Date objects to ISO strings explicitly
5 if (this && this[key] instanceof Date) {
6 return this[key].toISOString();
7 }
8 return value;
9});
10console.log(jsonCustom); // {"name":"Carol","joined":"2020-01-01T12:00:00.000Z"}
- Em um
replacerdo tipo função, a chave e o valor são passados e o valor retornado é usado no JSON final.thisrefere-se ao objeto pai, portanto pode ser usado para conversões aninhadas.
Os fundamentos do JSON.parse()
JSON.parse converte uma string JSON de volta para um objeto. Envolva com try/catch para que você possa lidar com JSON inválido.
1// Parse a JSON string into an object and handle parsing errors.
2const jsonText = '{"title":"Example","count":42}';
3try {
4 const parsed = JSON.parse(jsonText);
5 console.log(parsed.title); // Example
6} catch (err) {
7 console.error("Invalid JSON:", err.message);
8}- Se a string for inválida, uma exceção será lançada, então sempre inclua o tratamento de exceções ao lidar com fontes externas.
Restauração personalizada usando reviver (exemplo de restauração de Date)
Ao usar o segundo argumento reviver do JSON.parse, você pode realizar a restauração de valores. Aqui está um exemplo de como converter uma data em string armazenada de volta para um objeto Date.
1// Use a reviver to turn ISO date strings back into Date objects.
2const jsonWithDate = '{"name":"Dana","joined":"2021-06-15T09:00:00.000Z"}';
3const obj = JSON.parse(jsonWithDate, (key, value) => {
4 // A simple check for ISO date-like strings
5 if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
6 return new Date(value);
7 }
8 return value;
9});
10console.log(obj.joined instanceof Date); // true
reviveré chamado para cada chave, e o valor retornado é utilizado no objeto final. Por favor, realize uma verificação rigorosa do formato da data de acordo com sua aplicação.
Formatação legível e o argumento space
Para saída com indentação e melhor legibilidade, passe um número ou string como terceiro argumento para JSON.stringify.
1// Pretty-print an object with 2-space indentation for readability.
2const config = { host: "localhost", port: 3000, debug: true };
3const pretty = JSON.stringify(config, null, 2);
4console.log(pretty);
5/* {
6 "host": "localhost",
7 "port": 3000,
8 "debug": true
9} */- Para JSON que deve ser lido por pessoas, como logs ou arquivos de configuração, é útil especificar a indentação. No entanto, esteja ciente de que isso aumenta o tamanho.
Como lidar com referências circulares
JSON.stringify lança um TypeError se houver uma referência circular. Uma solução comum é criar um replacer usando um conjunto seen para evitar referências circulares.
1// Safely stringify objects that may contain circular references.
2function safeStringify(value) {
3 const seen = new WeakSet();
4 return JSON.stringify(value, (key, val) => {
5 if (val && typeof val === "object") {
6 if (seen.has(val)) return "[Circular]";
7 seen.add(val);
8 }
9 return val;
10 });
11}
12
13const a = { name: "A" };
14a.self = a;
15console.log(safeStringify(a)); // {"name":"A","self":"[Circular]"}
- Ao usar um
WeakSet, você pode detectar referências circulares evitando vazamentos de memória. No caso de uma referência circular, retorna"[Circular]". Também é possível atribuir um ID de referência em vez de"[Circular]".
Serialização personalizada com o método toJSON
Se você definir um método toJSON em um objeto, JSON.stringify usará o valor retornado por ele. Isso é útil quando você deseja incorporar regras de conversão para cada tipo.
1// Define toJSON on a class to customize its JSON representation.
2class Point {
3 constructor(x, y) {
4 this.x = x;
5 this.y = y;
6 }
7 toJSON() {
8 // This will be used by JSON.stringify
9 return { x: this.x, y: this.y, type: "Point" };
10 }
11}
12
13const p = new Point(10, 20);
14console.log(JSON.stringify(p)); // {"x":10,"y":20,"type":"Point"}
- O
toJSONpermite definir regras de serialização no nível do objeto, tornando-o mais localizado e intuitivo do que usarreplacer.
Limitações e cuidados com o JSON
Exemplos notáveis que não podem ser convertidos para JSON incluem undefined, funções, Symbol, BigInt e referências circulares. Atente também para a precisão numérica (como grandes inteiros e arredondamento de ponto flutuante IEEE).
1// Demonstrate values that can't be represented in JSON.
2const sample = {
3 a: undefined,
4 b: function () {},
5 c: Symbol("s"),
6 d: 9007199254740993n // BigInt (note: JSON.stringify will throw on BigInt)
7};
8// JSON.stringify will throw for BigInt and will drop undefined, functions, symbols in objects.
9try {
10 console.log(JSON.stringify(sample));
11} catch (err) {
12 console.error("Error during stringify:", err.message);
13}- Ao lidar com
BigInt, converta-o para string ou defina sua representação usando umreplacerpersonalizado outoJSON.
Segurança (ao lidar com JSON não confiável)
JSON.parse em si é seguro e considerado mais seguro que eval, mas é perigoso confiar no objeto analisado e usá-lo diretamente para acesso de propriedades ou consultas ao banco de dados. Sempre valide e verifique se os dados estão em conformidade com o esquema esperado.
1// Parse external JSON and validate expected properties before use.
2const external = '{"username":"eve","role":"user"}';
3const parsed = JSON.parse(external);
4if (typeof parsed.username === "string" && ["user","admin"].includes(parsed.role)) {
5 console.log("Safe to use parsed.username and parsed.role.");
6} else {
7 throw new Error("Invalid payload");
8}- Para validação de entrada (validação de esquema), usar bibliotecas como
ajvé uma abordagem robusta.
Considerações de desempenho
Serializar e desserializar objetos grandes com frequência gera uma carga considerável na CPU e na memória. Se necessário, considere enviar apenas as diferenças, usar formatos binários (como MessagePack), ou streaming (processamento sequencial dos dados). Em ambientes de navegador, existem casos em que você pode usar structuredClone (para cópia) ou objetos transferíveis em postMessage.
Dicas específicas (resumido)
Você também pode considerar os seguintes pontos:.
- Para logs, evite o pretty-print e use JSON em linha única para reduzir o tamanho.
- Objetos que são serializados com frequência devem ser simplificados previamente, por exemplo removendo propriedades desnecessárias.
- Use o
replacerpara minimizar a travessia e excluir propriedades desnecessárias.
Exemplo prático: fluxo de envio/recebimento de requisições API
Por fim, aqui está uma sequência mostrando como converter um objeto em JSON de forma segura para envio ao servidor e restaurar uma data a partir da resposta recebida.
1// Prepare payload, stringify safely, send via fetch, and revive dates on response.
2async function sendUserUpdate(url, user) {
3 // Remove sensitive info before sending
4 const payload = JSON.stringify(user, (k, v) => (k === "password" ? undefined : v));
5 const res = await fetch(url, {
6 method: "POST",
7 headers: { "Content-Type": "application/json" },
8 body: payload
9 });
10
11 const text = await res.text();
12 // Reviver: convert ISO date strings back to Date
13 const data = JSON.parse(text, (key, value) => {
14 if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
15 return new Date(value);
16 }
17 return value;
18 });
19 return data;
20}- Neste exemplo,
passwordé excluída antes do envio e a data é restaurada peloreviverapós o recebimento. Na operação real, será necessário adicionar tratamento de erros e processamento de timeout.
Resumo
Usando JSON.stringify() e JSON.parse(), você pode converter entre objetos e strings. Você pode personalizar o processo de conversão usando replacer e reviver, e se implementar toJSON em uma classe, também pode controlar cada objeto individualmente. Referências circulares, BigInt, funções, etc. não podem ser tratados como estão, então é necessário processá-los previamente.
Sempre valide as entradas externas e certifique-se de que informações sensíveis não estejam incluídas em logs ou comunicações. Se o tamanho dos dados for grande, é eficiente evitar pretty-print, considerar transmissão diferencial ou usar formatos binários.
Você pode acompanhar o artigo acima usando o Visual Studio Code em nosso canal do YouTube. Por favor, confira também o canal do YouTube.