Working with JSON in JavaScript: A Complete Guide
JSON and JavaScript go hand in hand. Whether you're fetching data from APIs, storing user preferences, or configuring applications, knowing how to work with JSON in JavaScript is essential for every web developer.
JSON.parse() - String to Object
JSON.parse() converts a JSON string into a JavaScript object. It's the primary method for consuming JSON data in your application.
const jsonString = '{"name": "John", "age": 30}';
const user = JSON.parse(jsonString);
console.log(user.name); // "John"
console.log(user.age); // 30 (number, not string)The Reviver Function
The second parameter is a "reviver" function that lets you transform values during parsing:
const data = '{"date": "2026-01-29T12:00:00Z"}';
const result = JSON.parse(data, (key, value) => {
if (key === 'date') {
return new Date(value);
}
return value;
});
console.log(result.date instanceof Date); // trueJSON.stringify() - Object to String
JSON.stringify() converts a JavaScript value to a JSON string. It's used when you need to store or transmit data.
const user = { name: "John", age: 30 };
// Compact JSON
JSON.stringify(user);
// '{"name":"John","age":30}'
// Pretty-printed with 2-space indent
JSON.stringify(user, null, 2);
// {
// "name": "John",
// "age": 30
// }The Replacer Parameter
The second parameter controls which properties are included:
const user = {
name: "John",
password: "secret123",
email: "[email protected]"
};
// Array: include only these keys
JSON.stringify(user, ['name', 'email']);
// '{"name":"John","email":"[email protected]"}'
// Function: transform values
JSON.stringify(user, (key, value) => {
if (key === 'password') return undefined; // omit
return value;
});
// '{"name":"John","email":"[email protected]"}'Fetching JSON from APIs
The Fetch API is the modern way to make HTTP requests in JavaScript. It works seamlessly with JSON:
// Using async/await (recommended)
async function getUser(id) {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const user = await response.json(); // Parses JSON automatically
return user;
}
// Usage
const user = await getUser(123);
console.log(user.name);async function createUser(userData) {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
// Usage
const newUser = await createUser({
name: 'Jane',
email: '[email protected]'
});Error Handling
Always wrap JSON operations in try-catch blocks to handle parsing errors gracefully:
function safeJsonParse(jsonString, defaultValue = null) {
try {
return JSON.parse(jsonString);
} catch (error) {
console.error('JSON parse error:', error.message);
return defaultValue;
}
}
// Usage
const data = safeJsonParse('{"valid": true}'); // { valid: true }
const fallback = safeJsonParse('not json', {}); // {}
const invalid = safeJsonParse('{"broken"'); // nullWorking with localStorage
localStorage only stores strings, so JSON is essential for storing complex data:
// Helper functions for localStorage + JSON
const storage = {
get(key, defaultValue = null) {
const item = localStorage.getItem(key);
if (item === null) return defaultValue;
try {
return JSON.parse(item);
} catch {
return defaultValue;
}
},
set(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
remove(key) {
localStorage.removeItem(key);
}
};
// Usage
storage.set('user', { name: 'John', theme: 'dark' });
const user = storage.get('user'); // { name: 'John', theme: 'dark' }
const missing = storage.get('unknown', {}); // {}Advanced Techniques
Deep Cloning Objects
// Quick deep clone (works for JSON-safe values) const clone = JSON.parse(JSON.stringify(original)); // Note: This doesn't work with: // - Functions // - undefined // - Symbol // - Circular references // - Date objects (become strings) // - Map, Set, RegExp
Custom toJSON Method
class User {
constructor(name, password) {
this.name = name;
this.password = password;
}
// Custom serialization
toJSON() {
return {
name: this.name,
// password is NOT included
};
}
}
const user = new User('John', 'secret');
JSON.stringify(user);
// '{"name":"John"}' - password excluded!BigInt Handling
// BigInt throws an error by default
// JSON.stringify({ big: 123n }); // TypeError!
// Solution: custom replacer
JSON.stringify({ big: 123n }, (key, value) =>
typeof value === 'bigint' ? value.toString() : value
);
// '{"big":"123"}'Common Pitfalls
Date objects are converted to ISO strings. Parse them back with a reviver or new Date().
Properties with undefined values are removed from the output.
Special number values are converted to null in JSON.
Objects referencing themselves will cause a TypeError.
Quick Reference
| Method | Purpose | Example |
|---|---|---|
| JSON.parse(str) | String → Object | JSON.parse('{"a":1}') |
| JSON.stringify(obj) | Object → String | JSON.stringify({a:1}) |
| res.json() | Parse fetch response | await res.json() |
| structuredClone() | Deep clone (modern) | structuredClone(obj) |
Practice working with JSON!