JSON (JavaScript Object Notation) is the universal language of data exchange on the web. APIs send JSON, browsers store JSON, and developers work with JSON daily. JavaScript provides two essential methods: JSON.parse() converts JSON strings into JavaScript objects, and JSON.stringify() converts JavaScript objects into JSON strings. Mastering these methods is crucial for working with APIs, storing data, and building modern web applications. Let's dive into JSON!
What is JSON?
JSON (JavaScript Object Notation)
- Text-based data format (not JavaScript code)
- Language-independent (used by all languages)
- Lightweight and easy to read
- Standard format for APIs and data storage
- Looks similar to JavaScript objects, but stricter
// Valid JSON (text format)
{
"name": "Alice",
"age": 25,
"active": true,
"hobbies": ["reading", "coding", "hiking"],
"address": {
"city": "NYC",
"zip": "10001"
}
}
// JSON Rules:
// - Property names MUST be in double quotes
// - Strings MUST use double quotes (not single)
// - No trailing commas
// - No comments
// - No functions or undefined
// - Limited data types: string, number, boolean, null, object, arrayJSON vs JavaScript Object Literal
// JavaScript Object (code)
let jsObject = {
name: 'Alice', // Unquoted keys OK
age: 25,
greet: function() { // Functions OK
console.log('Hi');
},
hobbies: ['reading'], // Trailing comma OK
};
// JSON String (text)
let jsonString = '{"name":"Alice","age":25,"hobbies":["reading"]}';
// - Keys must be quoted
// - No functions
// - No trailing commas
// - Must be valid text
// JSON is a text representation of data
// JavaScript objects are actual objects in memoryJSON.parse() - String to Object
JSON.parse() converts a JSON string into a JavaScript value.
Basic Usage
// Parse JSON string to object
let jsonString = '{"name":"Alice","age":25}';
let obj = JSON.parse(jsonString);
console.log(obj); // { name: 'Alice', age: 25 }
console.log(obj.name); // "Alice"
console.log(obj.age); // 25
console.log(typeof obj); // "object"
// Parse JSON array
let jsonArray = '[1, 2, 3, 4, 5]';
let arr = JSON.parse(jsonArray);
console.log(arr); // [1, 2, 3, 4, 5]
console.log(arr[0]); // 1
// Parse nested JSON
let jsonNested = '{"user":{"name":"Bob","age":30},"active":true}';
let nested = JSON.parse(jsonNested);
console.log(nested.user.name); // "Bob"
console.log(nested.active); // true
// Parse different types
console.log(JSON.parse('true')); // true
console.log(JSON.parse('false')); // false
console.log(JSON.parse('null')); // null
console.log(JSON.parse('123')); // 123
console.log(JSON.parse('"hello"')); // "hello"Error Handling
// Invalid JSON throws SyntaxError
try {
// Missing quotes around key
let bad1 = JSON.parse('{name: "Alice"}');
} catch (error) {
console.log('Error:', error.message);
// "Unexpected token n in JSON at position 1"
}
try {
// Single quotes (must be double)
let bad2 = JSON.parse("{'name': 'Alice'}");
} catch (error) {
console.log('Error:', error.message);
}
try {
// Trailing comma
let bad3 = JSON.parse('{"name":"Alice",}');
} catch (error) {
console.log('Error:', error.message);
}
// Always use try-catch when parsing untrusted JSON
function safeParse(jsonString) {
try {
return JSON.parse(jsonString);
} catch (error) {
console.error('Failed to parse JSON:', error.message);
return null;
}
}
let result = safeParse('invalid json');
console.log(result); // null
// Real-world: API response
async function fetchUser(userId) {
try {
let response = await fetch(`/api/users/${userId}`);
let text = await response.text();
try {
let data = JSON.parse(text);
return data;
} catch (parseError) {
console.error('Invalid JSON from server');
return null;
}
} catch (error) {
console.error('Network error');
return null;
}
}Reviver Function (Advanced)
// JSON.parse(text, reviver)
// Reviver function transforms values during parsing
// Example 1: Convert date strings to Date objects
let jsonWithDate = '{"name":"Alice","createdAt":"2024-01-15T10:00:00.000Z"}';
let obj = JSON.parse(jsonWithDate, (key, value) => {
// Check if value looks like ISO date string
if (typeof value === 'string' && /^d{4}-d{2}-d{2}T/.test(value)) {
return new Date(value);
}
return value;
});
console.log(obj.createdAt); // Date object
console.log(obj.createdAt instanceof Date); // true
// Example 2: Transform specific properties
let jsonData = '{"price":"99.99","quantity":"5"}';
let data = JSON.parse(jsonData, (key, value) => {
// Convert string numbers to actual numbers
if (key === 'price' || key === 'quantity') {
return parseFloat(value);
}
return value;
});
console.log(typeof data.price); // "number"
console.log(typeof data.quantity); // "number"
// Example 3: Filter properties
let jsonFull = '{"name":"Alice","password":"secret","age":25}';
let filtered = JSON.parse(jsonFull, (key, value) => {
// Remove password field
if (key === 'password') {
return undefined; // Omit this property
}
return value;
});
console.log(filtered); // { name: 'Alice', age: 25 }JSON.stringify() - Object to String
JSON.stringify() converts a JavaScript value to a JSON string.
Basic Usage
// Stringify object to JSON
let obj = { name: 'Alice', age: 25 };
let json = JSON.stringify(obj);
console.log(json); // '{"name":"Alice","age":25}'
console.log(typeof json); // "string"
// Stringify array
let arr = [1, 2, 3, 4, 5];
let jsonArr = JSON.stringify(arr);
console.log(jsonArr); // '[1,2,3,4,5]'
// Stringify nested structures
let user = {
name: 'Bob',
age: 30,
address: {
city: 'NYC',
zip: '10001'
},
hobbies: ['reading', 'coding']
};
let jsonUser = JSON.stringify(user);
console.log(jsonUser);
// '{"name":"Bob","age":30,"address":{"city":"NYC","zip":"10001"},"hobbies":["reading","coding"]}'
// Stringify different types
console.log(JSON.stringify(true)); // 'true'
console.log(JSON.stringify(false)); // 'false'
console.log(JSON.stringify(null)); // 'null'
console.log(JSON.stringify(123)); // '123'
console.log(JSON.stringify('hello')); // '"hello"'What Gets Converted (and What Doesn't)
let obj = {
// These convert properly
string: 'hello',
number: 42,
boolean: true,
nullValue: null,
array: [1, 2, 3],
nested: { key: 'value' },
// These are omitted or converted
func: function() { return 'hi'; }, // Omitted
undef: undefined, // Omitted
symbol: Symbol('id'), // Omitted
date: new Date(), // Becomes string
regex: /test/, // Becomes {}
nan: NaN, // Becomes null
infinity: Infinity // Becomes null
};
let json = JSON.stringify(obj);
console.log(json);
// {
// "string":"hello",
// "number":42,
// "boolean":true,
// "nullValue":null,
// "array":[1,2,3],
// "nested":{"key":"value"},
// "date":"2024-01-15T10:00:00.000Z",
// "regex":{},
// "nan":null,
// "infinity":null
// }
// Notice: func, undef, symbol are missing!
// Array behavior (keeps undefined as null)
let arr = [1, undefined, 3, function() {}, 5];
console.log(JSON.stringify(arr));
// '[1,null,3,null,5]'Pretty Printing (Formatting)
// JSON.stringify(value, replacer, space)
let obj = {
name: 'Alice',
age: 25,
hobbies: ['reading', 'coding']
};
// Default: compact (no spacing)
console.log(JSON.stringify(obj));
// '{"name":"Alice","age":25,"hobbies":["reading","coding"]}'
// With indentation (space = number of spaces)
console.log(JSON.stringify(obj, null, 2));
// {
// "name": "Alice",
// "age": 25,
// "hobbies": [
// "reading",
// "coding"
// ]
// }
// With tab indentation
console.log(JSON.stringify(obj, null, ' '));
// Save pretty JSON to file (Node.js)
const fs = require('fs');
fs.writeFileSync('data.json', JSON.stringify(obj, null, 2));
// Compact for APIs, pretty for debugging
let compactJSON = JSON.stringify(data); // Send to API
let prettyJSON = JSON.stringify(data, null, 2); // Log to consoleReplacer Function (Advanced)
// JSON.stringify(value, replacer, space)
// Replacer function transforms values during stringification
// Example 1: Remove sensitive data
let user = {
name: 'Alice',
email: 'alice@test.com',
password: 'secret123',
age: 25
};
let safeJSON = JSON.stringify(user, (key, value) => {
// Remove password
if (key === 'password') {
return undefined; // Omit this property
}
return value;
});
console.log(safeJSON);
// '{"name":"Alice","email":"alice@test.com","age":25}'
// Example 2: Transform values
let product = {
name: 'Laptop',
price: 999.99,
inStock: true
};
let transformed = JSON.stringify(product, (key, value) => {
// Round prices
if (key === 'price') {
return Math.round(value);
}
// Convert booleans to strings
if (typeof value === 'boolean') {
return value ? 'Yes' : 'No';
}
return value;
});
console.log(transformed);
// '{"name":"Laptop","price":1000,"inStock":"Yes"}'
// Example 3: Replacer array (whitelist properties)
let full = {
id: 1,
name: 'Alice',
password: 'secret',
email: 'alice@test.com',
internal: 'data'
};
// Only include these properties
let partial = JSON.stringify(full, ['id', 'name', 'email']);
console.log(partial);
// '{"id":1,"name":"Alice","email":"alice@test.com"}'Practical Patterns
Pattern 1: Deep Clone Objects
// Deep clone using JSON (simple objects only)
let original = {
name: 'Alice',
age: 25,
address: {
city: 'NYC',
zip: '10001'
},
hobbies: ['reading', 'coding']
};
// JSON deep clone
let clone = JSON.parse(JSON.stringify(original));
// Modify clone
clone.address.city = 'LA';
clone.hobbies.push('hiking');
console.log(original.address.city); // "NYC" (unchanged!)
console.log(original.hobbies); // ["reading", "coding"] (unchanged!)
console.log(clone.address.city); // "LA"
console.log(clone.hobbies); // ["reading", "coding", "hiking"]
// Warning: Doesn't work with:
// - Functions
// - Dates (become strings)
// - undefined
// - Symbols
// - Circular references
// For complex objects, use structuredClone() or libraries like lodash
let betterClone = structuredClone(original); // Modern browsersPattern 2: Storing Objects in localStorage
// localStorage only stores strings
// Use JSON to store objects
// Save object
let user = {
name: 'Alice',
settings: {
theme: 'dark',
notifications: true
}
};
localStorage.setItem('user', JSON.stringify(user));
// Load object
let savedUser = JSON.parse(localStorage.getItem('user'));
console.log(savedUser.name); // "Alice"
console.log(savedUser.settings.theme); // "dark"
// Helper functions
function saveToStorage(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
console.error('Failed to save:', error);
return false;
}
}
function loadFromStorage(key, defaultValue = null) {
try {
let item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (error) {
console.error('Failed to load:', error);
return defaultValue;
}
}
// Usage
saveToStorage('settings', { theme: 'dark', fontSize: 16 });
let settings = loadFromStorage('settings', { theme: 'light' });Pattern 3: API Request/Response
// Sending JSON to API
async function createUser(userData) {
try {
let response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData) // Convert to JSON
});
let result = await response.json(); // Parse JSON response
return result;
} catch (error) {
console.error('Error:', error);
return null;
}
}
// Usage
let newUser = {
name: 'Alice',
email: 'alice@test.com',
age: 25
};
let created = await createUser(newUser);
console.log(created);
// Getting JSON from API
async function getUsers() {
try {
let response = await fetch('/api/users');
// Check if response is JSON
let contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new Error('Response is not JSON');
}
let users = await response.json(); // Parses automatically
return users;
} catch (error) {
console.error('Error:', error);
return [];
}
}Pattern 4: Configuration Files
// Save/load configuration
class Config {
constructor() {
this.settings = this.load();
}
load() {
try {
let config = localStorage.getItem('appConfig');
return config ? JSON.parse(config) : this.getDefaults();
} catch (error) {
console.error('Failed to load config:', error);
return this.getDefaults();
}
}
save() {
try {
localStorage.setItem('appConfig', JSON.stringify(this.settings));
return true;
} catch (error) {
console.error('Failed to save config:', error);
return false;
}
}
getDefaults() {
return {
theme: 'light',
language: 'en',
notifications: true,
autoSave: true,
fontSize: 14
};
}
get(key) {
return this.settings[key];
}
set(key, value) {
this.settings[key] = value;
this.save();
}
reset() {
this.settings = this.getDefaults();
this.save();
}
}
// Usage
let config = new Config();
console.log(config.get('theme')); // "light"
config.set('theme', 'dark');
config.set('fontSize', 16);
console.log(config.settings);JSON Parse and Stringify
Master data serialization
console.log() to see your output in the console above.Key Takeaways
- JSON is a text-based data format, not JavaScript code
JSON.parse()converts JSON string to JavaScript valueJSON.stringify()converts JavaScript value to JSON string- Always use try-catch when parsing untrusted JSON
- JSON supports: objects, arrays, strings, numbers, booleans, null
- JSON omits: functions, undefined, symbols
- Use
JSON.stringify(obj, null, 2)for pretty printing - Replacer function filters/transforms during stringify
- Reviver function transforms during parse
- Perfect for APIs, localStorage, and configuration
What's Next?
You now understand JSON and can convert between JavaScript objects and JSON strings! You've learned JSON.parse() and JSON.stringify(), error handling, and practical patterns for working with data.
In the next lesson, we'll explore the Fetch API and HTTP Requestsβlearning to make API calls, handle responses, and work with real-world data from servers!
πͺ Practice Challenge:
Before moving on, try:
- Parse a JSON string from an API response
- Stringify an object and save it to localStorage
- Create a deep clone of a nested object using JSON
- Use a replacer function to remove sensitive data
- Build storage helpers with JSON parse/stringify and error handling