Working with JSON in JavaScript
JavaScript has built-in support for JSON through the global JSON object.
This guide covers everything you need to know about working with JSON in JavaScript,
from basic parsing to advanced techniques.
Parsing JSON
Use JSON.parse() to convert a JSON string into a JavaScript object:
// Parse a JSON string
const jsonString = '{"name": "John", "age": 30, "city": "New York"}';
const data = JSON.parse(jsonString);
console.log(data.name); // "John"
console.log(data.age); // 30
// Parse JSON with error handling
function safeJsonParse(str) {
try {
return { success: true, data: JSON.parse(str) };
} catch (error) {
return { success: false, error: error.message };
}
}
const result = safeJsonParse('{"valid": true}');
if (result.success) {
console.log(result.data);
} Stringifying Objects
Use JSON.stringify() to convert a JavaScript object to a JSON string:
const user = {
name: "Jane",
age: 25,
isActive: true,
hobbies: ["reading", "coding"]
};
// Basic stringify
const json = JSON.stringify(user);
// '{"name":"Jane","age":25,"isActive":true,"hobbies":["reading","coding"]}'
// Pretty print with 2 spaces
const prettyJson = JSON.stringify(user, null, 2);
/*
{
"name": "Jane",
"age": 25,
"isActive": true,
"hobbies": [
"reading",
"coding"
]
}
*/
// Pretty print with tab
const tabbedJson = JSON.stringify(user, null, '\t'); Filtering with Replacer
The second argument of JSON.stringify() can be used to filter or transform values:
const user = {
name: "John",
password: "secret123",
email: "john@example.com",
age: 30
};
// Filter specific keys
const publicData = JSON.stringify(user, ["name", "email", "age"]);
// '{"name":"John","email":"john@example.com","age":30}'
// Transform values with a function
const transformed = JSON.stringify(user, (key, value) => {
if (key === "password") return undefined; // Exclude
if (key === "email") return value.toLowerCase(); // Transform
return value;
});
// '{"name":"John","email":"john@example.com","age":30}' Reviver Function
The JSON.parse() method accepts a reviver function to transform parsed values:
const json = '{"name": "John", "birthDate": "1990-05-15T00:00:00.000Z"}';
// Convert date strings to Date objects
const data = JSON.parse(json, (key, value) => {
if (key === "birthDate") {
return new Date(value);
}
return value;
});
console.log(data.birthDate instanceof Date); // true
console.log(data.birthDate.getFullYear()); // 1990 Validating JSON
Here's a robust function to validate JSON strings:
function isValidJson(str) {
try {
JSON.parse(str);
return true;
} catch (e) {
return false;
}
}
// With detailed error reporting
function validateJson(str) {
try {
const data = JSON.parse(str);
return {
valid: true,
data: data,
type: Array.isArray(data) ? 'array' : typeof data
};
} catch (error) {
// Extract line and column from error message
const match = error.message.match(/position (\d+)/);
const position = match ? parseInt(match[1]) : 0;
const lines = str.substring(0, position).split('\n');
return {
valid: false,
error: error.message,
line: lines.length,
column: lines[lines.length - 1].length + 1
};
}
}
console.log(validateJson('{"name": "John"}'));
// { valid: true, data: { name: 'John' }, type: 'object' }
console.log(validateJson('{invalid}'));
// { valid: false, error: '...', line: 1, column: 2 } Deep Cloning Objects
JSON can be used for deep cloning objects (with limitations):
const original = {
name: "John",
address: {
city: "New York",
zip: "10001"
},
hobbies: ["reading", "gaming"]
};
// Deep clone using JSON
const clone = JSON.parse(JSON.stringify(original));
// Modify clone without affecting original
clone.address.city = "Los Angeles";
console.log(original.address.city); // "New York" (unchanged)
// Note: This doesn't work with:
// - Functions
// - undefined values
// - Symbol properties
// - Date objects (become strings)
// - Map, Set, RegExp (become empty objects) Working with JSON Files (Node.js)
const fs = require('fs');
const path = require('path');
// Read JSON file synchronously
const data = JSON.parse(fs.readFileSync('data.json', 'utf8'));
// Read JSON file asynchronously
fs.readFile('data.json', 'utf8', (err, content) => {
if (err) throw err;
const data = JSON.parse(content);
console.log(data);
});
// Using promises
const fsPromises = require('fs').promises;
async function readJsonFile(filePath) {
const content = await fsPromises.readFile(filePath, 'utf8');
return JSON.parse(content);
}
// Write JSON file
const newData = { name: "Jane", age: 28 };
fs.writeFileSync('output.json', JSON.stringify(newData, null, 2)); Fetch API with JSON
// GET request
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
// POST request with JSON body
async function postData(url, data) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
return response.json();
}
// Usage
postData('https://api.example.com/users', {
name: 'John',
email: 'john@example.com'
}).then(result => console.log(result)); Handling Circular References
JSON.stringify() throws an error for circular references. Here's how to handle them:
// This will throw an error
const obj = { name: "John" };
obj.self = obj; // Circular reference
// JSON.stringify(obj); // TypeError: Converting circular structure to JSON
// Solution: Custom replacer to handle circular references
function stringifyWithCircular(obj) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return '[Circular Reference]';
}
seen.add(value);
}
return value;
}, 2);
}
console.log(stringifyWithCircular(obj));
/*
{
"name": "John",
"self": "[Circular Reference]"
}
*/ Best Practices
- Always wrap
JSON.parse()in a try-catch block - Validate JSON from external sources before using it
- Use
JSON.stringify()with a replacer to exclude sensitive data - Consider using
structuredClone()for deep cloning (modern browsers) - Be aware of JSON limitations (no functions, undefined, circular refs)