Come Formattare JSON in JavaScript — 5 Metodi
JSON è ovunque: risposte API, file di configurazione, esportazioni di database, pipeline di log. Ma l'output JSON grezzo è spesso un blob compatto — nessun a capo, nessuna indentazione, chiavi nell'ordine che il serializzatore ha scelto di sputarle fuori. Questo rende il debug doloroso e la collaborazione più difficile del necessario.
JavaScript ti offre diversi modi per formattare JSON, dalla JSON.stringify built-in alle librerie di streaming per file troppo grandi da caricare in memoria. Questa guida illustra cinque metodi pratici, coprendo i casi più comuni e i casi limite che colgono di sorpresa gli sviluppatori.
Metodo 1: JSON.stringify con Indentazione
L'approccio più semplice è già integrato nel linguaggio. JSON.stringify accetta tre argomenti: il valore da serializzare, un replacer (di più nel Metodo 2) e un parametro space che controlla l'indentazione.
const data = {
name: "Alice",
role: "engineer",
skills: ["JavaScript", "TypeScript", "Node.js"],
active: true,
};
// Indentazione 2 spazi (default comune)
console.log(JSON.stringify(data, null, 2));
// Indentazione 4 spazi
console.log(JSON.stringify(data, null, 4));
// Indentazione con tabulazione
console.log(JSON.stringify(data, null, "\t"));
Con null, 2, l'output appare così:
{
"name": "Alice",
"role": "engineer",
"skills": [
"JavaScript",
"TypeScript",
"Node.js"
],
"active": true
}
Due spazi è la convenzione più comune nei progetti JavaScript — corrisponde al default in ESLint, Prettier e alla maggior parte delle guide di stile. Quattro spazi è comune negli strumenti adiacenti a Python. Quando space viene omesso o impostato su 0, l'output è una stringa compatta su una riga — ideale per la trasmissione su rete.
Puoi anche formattare JSON istantaneamente nel browser usando lo strumento JSON Formatter — incolla JSON grezzo, ottieni output formattato e copia il risultato senza scrivere codice.
Metodo 2: Funzione Replacer Personalizzata
Il secondo argomento di JSON.stringify — il replacer — è una funzione o array che filtra e trasforma i valori prima della serializzazione. È qui che ottieni il vero controllo su cosa finisce nell'output.
La forma array è l'approccio più semplice per il whitelisting delle chiavi:
const user = {
id: 42,
name: "Bob",
password: "s3cr3t",
email: "bob@example.com",
createdAt: new Date(),
};
// Replacer array: includi solo le chiavi elencate
const safeJson = JSON.stringify(user, ["id", "name", "email"], 2);
console.log(safeJson);
// {
// "id": 42,
// "name": "Bob",
// "email": "bob@example.com"
// }
La forma funzione ti dà il controllo per ogni valore. Restituisci il valore per includerlo, restituisci undefined per eliminarlo, o restituisci un valore trasformato:
function replacer(key, value) {
// Elimina le chiavi che iniziano con underscore (convenzione privata)
if (key.startsWith("_")) return undefined;
// Maschera i campi sensibili
if (key === "password" || key === "token") return "[REDACTED]";
// Converti gli oggetti Date in stringhe ISO esplicitamente
if (value instanceof Date) return value.toISOString();
return value;
}
const payload = {
id: 1,
name: "Carol",
password: "hunter2",
_internalFlag: true,
lastLogin: new Date("2026-05-01"),
};
console.log(JSON.stringify(payload, replacer, 2));
// {
// "id": 1,
// "name": "Carol",
// "password": "[REDACTED]",
// "lastLogin": "2026-05-01T00:00:00.000Z"
// } Il replacer viene eseguito ricorsivamente su ogni oggetto e array annidato. Questo schema è utile per le pipeline di logging dove vuoi rimuovere le credenziali prima di scrivere su disco o inviare a un servizio di osservabilità.
Metodo 3: Stampa Leggibile con Chiavi Ordinate
Gli oggetti JavaScript non garantiscono l'ordine delle chiavi (anche se V8 e la maggior parte dei motori preservano l'ordine di inserimento per le chiavi stringa). Quando hai bisogno di un output deterministico — per il diffing, la cache o le rappresentazioni canoniche — ordinare le chiavi alfabeticamente è la mossa giusta.
function sortedStringify(value, indent = 2) {
return JSON.stringify(value, sortReplacer, indent);
}
function sortReplacer(key, value) {
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
return Object.keys(value)
.sort()
.reduce((sorted, k) => {
sorted[k] = value[k];
return sorted;
}, {});
}
return value;
}
const config = {
version: "1.0",
author: "Dave",
dependencies: { typescript: "^5.4", eslint: "^9.0", astro: "^5.0" },
name: "my-project",
};
console.log(sortedStringify(config));
// {
// "author": "Dave",
// "dependencies": { "astro": "^5.0", "eslint": "^9.0", "typescript": "^5.4" },
// "name": "my-project",
// "version": "1.0"
// }
Le chiavi ordinate significano che i diff git mostrano solo le righe che sono effettivamente cambiate, anziché riordinamenti arbitrari da serializzatori diversi. Questo è particolarmente utile per package.json e file di configurazione simili aggiunti al controllo di versione.
Per la conversione di JSON in altri formati, lo strumento JSON to YAML e lo strumento JSON to CSV gestiscono anche l'ordinamento delle chiavi nel loro output.
Metodo 4: Formatta da una Stringa (Parse + Stringify)
Il JSON nel mondo reale arriva di solito come stringa — da una risposta fetch, una lettura di file, un incolla dagli appunti o una colonna TEXT del database. Devi prima analizzarlo, poi riformattarlo. Il pezzo critico è la gestione corretta degli errori: il JSON non valido genererà un'eccezione, e vuoi catturarla in modo elegante.
function formatJsonString(rawString, indent = 2) {
try {
const parsed = JSON.parse(rawString);
return { ok: true, result: JSON.stringify(parsed, null, indent) };
} catch (err) {
return { ok: false, error: err.message };
}
}
const raw = '{"name":"Eve","scores":[100,95,88],"active":true}';
const { ok, result, error } = formatJsonString(raw);
if (ok) {
console.log(result);
// {
// "name": "Eve",
// "scores": [100, 95, 88],
// "active": true
// }
} else {
console.error("Analisi fallita:", error);
}
// Input non valido
const bad = '{"name": "Eve", "broken":}';
const r2 = formatJsonString(bad);
// { ok: false, error: "Token inatteso '}'" } Racchiudere gli errori di parsing in un oggetto di ritorno strutturato rende questa funzione sicura da usare nei componenti UI e negli script di build senza circondare ogni sito di chiamata in un try/catch. La documentazione MDN per JSON.stringify copre la specifica completa dei parametri, e RFC 8259 definisce come appare il JSON valido a livello di protocollo.
Metodo 5: Streaming per File Grandi
I metodi 1-4 caricano tutti l'intera struttura JSON in memoria prima di formattarla. Per file nell'ordine delle centinaia di megabyte o multi-gigabyte, questo blocca il ciclo degli eventi di Node.js e può far crashare completamente il processo.
L'approccio in streaming legge il file in blocchi e scrive l'output formattato in modo incrementale. Per NDJSON (un oggetto JSON per riga, comune nei file di log e nelle esportazioni di database), un approccio basato su readline funziona senza dipendenze extra:
import { createReadStream, createWriteStream } from "node:fs";
import { createInterface } from "node:readline";
async function formatNdjsonFile(inputPath, outputPath) {
const rl = createInterface({
input: createReadStream(inputPath),
crlfDelay: Infinity,
});
const output = createWriteStream(outputPath);
for await (const line of rl) {
if (!line.trim()) continue;
try {
const obj = JSON.parse(line);
output.write(JSON.stringify(obj, null, 2) + "\n---\n");
} catch (e) {
output.write("[Riga JSON non valida: " + e.message + "]\n---\n");
}
}
output.end();
} NDJSON è il formato di streaming più semplice: ogni riga è un oggetto JSON valido e completo. Molti strumenti di esportazione lo supportano proprio perché è banalmente trasmissibile in streaming. Se controlli il formato delle grandi esportazioni di dati, preferisci NDJSON rispetto a un singolo enorme array JSON.
Casi Limite da Tenere a Mente
Questi sono gli scenari in cui la formattazione JSON standard fallisce silenziosamente o lancia eccezioni in modo inaspettato.
Riferimenti Circolari
JSON.stringify lancia un TypeError se un oggetto fa riferimento a se stesso direttamente o indirettamente. Risolvilo con un replacer che tiene traccia degli oggetti visitati usando un WeakSet:
function safeStringify(obj, indent = 2) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) return "[Circular]";
seen.add(value);
}
return value;
}, indent);
}
const a = { name: "circular" };
a.self = a;
console.log(safeStringify(a));
// { "name": "circular", "self": "[Circular]" }
Il WeakSet mantiene i riferimenti senza impedire la garbage collection, il che evita perdite di memoria nei processi di lunga durata.
Valori BigInt
JSON.stringify lancia un TypeError per i valori BigInt perché la specifica JSON non ha nessun tipo intero a 64 bit. Converti in stringa nel tuo replacer:
const data = { id: 9007199254740993n, value: 42 };
JSON.stringify(data, (key, value) =>
typeof value === "bigint" ? value.toString() : value
, 2);
// { "id": "9007199254740993", "value": 42 } Valori Map e Set
Map serializza come oggetto vuoto e Set serializza come array vuoto — non il loro contenuto. Convertili esplicitamente in un replacer:
const data = {
tags: new Set(["json", "javascript"]),
meta: new Map([["source", "api"]]),
};
JSON.stringify(data, (key, value) => {
if (value instanceof Set) return [...value];
if (value instanceof Map) return Object.fromEntries(value);
return value;
}, 2);
// { "tags": ["json", "javascript"], "meta": { "source": "api" } } Valori undefined
Le proprietà degli oggetti con valori undefined vengono eliminate silenziosamente. Gli slot degli array con undefined diventano null. Usa un replacer per convertire undefined in null quando hai bisogno di preservare tutte le chiavi:
const obj = { a: 1, b: undefined, c: null };
JSON.stringify(obj, null, 2);
// { "a": 1, "c": null } — "b" viene eliminato silenziosamente
// Soluzione:
JSON.stringify(obj, (key, value) =>
value === undefined ? null : value
, 2);
// { "a": 1, "b": null, "c": null } Formatta JSON Istantaneamente nel Browser
Se hai bisogno di formattare un blob JSON subito senza scrivere codice, il JSON Formatter di Toova lo gestisce in un click — incolla JSON grezzo, ottieni output formattato con indentazione a 2 o 4 spazi e copia il risultato. Nessuna registrazione, nessun caricamento di file, tutto viene eseguito localmente nel tuo browser.
Per le conversioni tra formati, JSON to YAML e JSON to CSV seguono lo stesso approccio privacy-first — i tuoi dati non lasciano mai il tuo dispositivo.
Conclusione
Per la maggior parte dei casi d'uso, JSON.stringify(obj, null, 2) è tutto ciò di cui hai bisogno. Aggiungi una funzione replacer quando hai bisogno di filtraggio, mascheratura o chiavi ordinate. Avvolgi JSON.parse in un try/catch quando gestisci input esterni. Ricorri allo streaming solo quando la dimensione del file rende impraticabile l'analisi sincrona. E tieni in mente i casi limite — riferimenti circolari, BigInt, Map/Set, undefined — quando lavori con forme di dati insolite.