Parsowanie JSON-a w JavaScript to coś, co będziesz robić setki razy jako web developer.
Na szczęście JavaScript ma do tego wbudowane wsparcie — bez żadnych bibliotek. Jest jednak więcej niuansów
dotyczących JSON.parse()
i JSON.stringify()
niż sugeruje dokumentacja. Przejdźmy przez to porządnie.
JSON.parse() — zamiana stringa na obiekt
JSON.parse() przyjmuje string w formacie JSON i konwertuje go na wartość JavaScript.
Ta wartość to zazwyczaj obiekt lub tablica, ale może być też stringiem, liczbą, boolanem lub null:
const jsonString = '{"name": "Alice", "age": 30, "active": true}';
const user = JSON.parse(jsonString);
console.log(user.name); // "Alice"
console.log(user.age); // 30
console.log(user.active); // true
console.log(typeof user); // "object"Pamiętaj, że na wejście musi trafić string. Częsty błąd to próba parsowania wartości, która już
jest obiektem — JSON.parse({}) rzuci SyntaxError, bo najpierw konwertuje obiekt na
"[object Object]", a to nie jest poprawny JSON.
Zawsze owijaj JSON.parse() w try/catch
Oto coś, o czym nikt ci nie mówi: JSON.parse() rzuca
SyntaxError,
gdy wejście nie jest poprawnym JSON-em. Jeśli parsujesz dane z API, wejścia użytkownika lub pliku, zawsze
powinieneś obsłużyć ten błąd. Jedna zniekształcona odpowiedź może crashnąć aplikację, jeśli tego nie zrobisz:
function safeParseJSON(str) {
try {
return { data: JSON.parse(str), error: null };
} catch (err) {
return { data: null, error: err.message };
}
}
const { data, error } = safeParseJSON('{"name": "Alice"}');
if (error) {
console.error('Invalid JSON:', error);
} else {
console.log(data.name); // "Alice"
}
// Handles bad input gracefully
const result = safeParseJSON('not json at all');
console.log(result.error); // "Unexpected token 'o', "not json "... is not valid JSON"Używam takiego wrappera w prawie każdym projekcie. Sprawia, że obsługa błędów jest spójna i zapobiega brzydkim nieprzechwyconym wyjątkom, które docierają do UI.
JSON.stringify() — zamiana obiektu na string
JSON.stringify() robi coś odwrotnego: konwertuje wartość JavaScript na string JSON.
Używasz tego przy wysyłaniu danych do API, zapisywaniu do localStorage lub pisaniu do pliku:
const user = {
name: "Bob",
age: 25,
roles: ["admin", "editor"],
password: "secret123" // we'll handle this later
};
// Basic usage
const jsonString = JSON.stringify(user);
// '{"name":"Bob","age":25,"roles":["admin","editor"],"password":"secret123"}'
// Pretty-printed (great for logs and file output)
const prettyJson = JSON.stringify(user, null, 2);
console.log(prettyJson);
// {
// "name": "Bob",
// "age": 25,
// "roles": ["admin", "editor"],
// "password": "secret123"
// }Trzeci argument JSON.stringify() to poziom wcięcia. Użycie 2
lub 4 daje czytelny wynik. Domyślnie (bez trzeciego argumentu) dostajesz zwarty, zminifikowany JSON
— lepszy do transmisji przez sieć.
Co stringify() po cichu pomija
To jedna z pułapek, na którą regularnie wpadają deweloperzy. JSON.stringify() po cichu pomija pewne wartości,
bo JSON ich nie obsługuje:
const data = {
name: "Alice",
greet: function() { return "hi"; }, // Functions → dropped
undef: undefined, // undefined → dropped
sym: Symbol("key"), // Symbols → dropped
nan: NaN, // NaN → null
inf: Infinity, // Infinity → null
date: new Date("2024-01-15") // Dates → ISO string
};
console.log(JSON.stringify(data, null, 2));
// {
// "name": "Alice",
// "nan": null,
// "inf": null,
// "date": "2024-01-15T00:00:00.000Z"
// }
// greet, undef, sym are GONEundefined, a potem
go sparsujemy, te klucze zupełnie znikną. Może to powodować subtelne bugi, jeśli twój kod sprawdza później
obj.key === undefined.Pobieranie JSON z API — wzorzec z prawdziwego życia
W praktyce większość parsowania JSON-a dzieje się podczas pobierania danych z API.
Fetch API
sprawia, że to proste — response.json() obsługuje parsowanie za ciebie:
async function getUser(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const user = await response.json(); // parses JSON automatically
return user;
} catch (err) {
console.error('Failed to fetch user:', err);
return null;
}
}
const user = await getUser(42);
if (user) {
console.log(`Hello, ${user.name}!`);
}response.json() to w zasadzie JSON.parse(await response.text()).
Też rzuca błąd, jeśli ciało odpowiedzi nie jest poprawnym JSON-em, więc warto obsłużyć to osobno
w kodzie produkcyjnym.
Praca z zagnieżdżonymi danymi JSON
Głęboko zagnieżdżony JSON jest powszechny w prawdziwych API. Oto jak bezpiecznie się po nim poruszać, nie crashując przy brakujących kluczach:
const apiResponse = {
"user": {
"profile": {
"address": {
"city": "Berlin"
}
}
}
};
// Unsafe — throws if any level is undefined
const city1 = apiResponse.user.profile.address.city; // "Berlin"
// Safe with optional chaining (ES2020+) — returns undefined instead of throwing
const city2 = apiResponse?.user?.profile?.address?.city; // "Berlin"
const zip = apiResponse?.user?.profile?.address?.zip; // undefined (not a crash)
// With a fallback using nullish coalescing
const country = apiResponse?.user?.profile?.address?.country ?? "Unknown";Optional chaining (?.)
oraz nullish coalescing (??)
to nowoczesne funkcje JavaScript — obie część
specyfikacji ECMAScript od 2020 roku — które
sprawiają, że praca z niepewnymi strukturami JSON jest znacznie bezpieczniejsza. Używaj ich swobodnie — są obsługiwane przez wszystkie
nowoczesne przeglądarki i Node.js 14+.
Funkcje replacer i reviver
Zarówno JSON.stringify(), jak i JSON.parse() przyjmują drugi argument,
który pozwala dostosować transformację. Są naprawdę przydatne w praktycznych scenariuszach:
// replacer: filter or transform values during stringify
const user = { name: "Alice", password: "s3cr3t", age: 30 };
const safe = JSON.stringify(user, ["name", "age"]); // only include these keys
// '{"name":"Alice","age":30}' — password is excluded
// reviver: transform values during parse
const dateJson = '{"name": "Alice", "createdAt": "2024-01-15T09:30:00Z"}';
const parsed = JSON.parse(dateJson, (key, value) => {
if (key === "createdAt") return new Date(value); // convert string to Date
return value;
});
console.log(parsed.createdAt instanceof Date); // true
console.log(parsed.createdAt.getFullYear()); // 2024Wzorzec reviver jest szczególnie przydatny do przywracania obiektów Date po
rundzie przez JSON, bo JSON nie ma natywnego typu daty.
Przydatne narzędzia
Podczas pracy z JSON-em w projektach JavaScript te narzędzia oszczędzają czas: JSON Formatter do pretty-printowania zminifikowanych odpowiedzi API, JSON Validator do sprawdzania błędów składni, JSON Path do odpytywania konkretnych pól z dużych payloadów oraz JSON Escape, gdy musisz osadzić JSON w stringu. Więcej szczegółów znajdziesz w dokumentacji JSON na MDN — jest doskonała.
Podsumowanie
JSON.parse() i JSON.stringify() to dwie funkcje, których potrzebujesz.
Kluczowe nawyki do wyrobienia: zawsze owijaj parse() w try/catch, używaj optional chaining do
dostępu do zagnieżdżonych danych i wiedz, co stringify() po cichu pomija. Opanuj te trzy rzeczy
i poradzisz sobie z 99% realnych scenariuszy JSON-owych bez niespodzianek.