javascript
examples
examples.js⚡javascript
/**
* ========================================
* 11.2 Working with JSON - Examples
* ========================================
*
* Comprehensive examples for JSON operations.
*/
/**
* ========================================
* EXAMPLE 1: Basic JSON.stringify
* ========================================
*/
console.log('--- Example 1: Basic JSON.stringify ---');
const user = {
name: 'John Doe',
age: 30,
email: 'john@example.com',
isActive: true,
scores: [95, 87, 92],
};
const jsonString = JSON.stringify(user);
console.log('JSON string:', jsonString);
console.log('Type:', typeof jsonString);
/**
* ========================================
* EXAMPLE 2: Pretty Printing
* ========================================
*/
console.log('\n--- Example 2: Pretty Printing ---');
const data = {
company: 'Tech Corp',
employees: [
{ name: 'Alice', role: 'Developer' },
{ name: 'Bob', role: 'Designer' },
],
locations: {
headquarters: 'New York',
branches: ['London', 'Tokyo'],
},
};
console.log('Compact:');
console.log(JSON.stringify(data));
console.log('\nPretty (2 spaces):');
console.log(JSON.stringify(data, null, 2));
console.log('\nPretty (4 spaces):');
console.log(JSON.stringify(data, null, 4));
console.log('\nPretty (custom):');
console.log(JSON.stringify(data, null, '→ '));
/**
* ========================================
* EXAMPLE 3: Replacer Function
* ========================================
*/
console.log('\n--- Example 3: Replacer Function ---');
const sensitiveData = {
username: 'johndoe',
password: 'secret123',
email: 'john@example.com',
ssn: '123-45-6789',
balance: 5000,
};
// Remove sensitive fields
const safeJson = JSON.stringify(sensitiveData, (key, value) => {
const sensitiveFields = ['password', 'ssn'];
if (sensitiveFields.includes(key)) {
return undefined; // Exclude from output
}
return value;
});
console.log('With sensitive data removed:', safeJson);
// Transform values
const transformedJson = JSON.stringify(sensitiveData, (key, value) => {
if (key === 'password') return '******';
if (key === 'ssn') return 'XXX-XX-' + value.slice(-4);
if (key === 'balance') return '$' + value.toLocaleString();
return value;
});
console.log('With transformed values:', transformedJson);
/**
* ========================================
* EXAMPLE 4: Replacer Array
* ========================================
*/
console.log('\n--- Example 4: Replacer Array ---');
const fullUser = {
id: 1,
username: 'johndoe',
email: 'john@example.com',
password: 'secret',
role: 'admin',
createdAt: new Date().toISOString(),
lastLogin: new Date().toISOString(),
};
// Only include specific fields
const publicFields = ['id', 'username', 'email', 'role'];
const publicJson = JSON.stringify(fullUser, publicFields, 2);
console.log('Public user data:');
console.log(publicJson);
/**
* ========================================
* EXAMPLE 5: toJSON Method
* ========================================
*/
console.log('\n--- Example 5: toJSON Method ---');
class Product {
constructor(id, name, price, cost) {
this.id = id;
this.name = name;
this.price = price;
this.cost = cost; // Internal, shouldn't be exposed
}
get profit() {
return this.price - this.cost;
}
toJSON() {
// Custom serialization
return {
id: this.id,
name: this.name,
price: this.price,
formattedPrice: `$${this.price.toFixed(2)}`,
// Note: cost is intentionally excluded
};
}
}
const product = new Product(1, 'Widget', 29.99, 15.0);
console.log('Product JSON:', JSON.stringify(product, null, 2));
/**
* ========================================
* EXAMPLE 6: Basic JSON.parse
* ========================================
*/
console.log('\n--- Example 6: Basic JSON.parse ---');
const jsonData = '{"name":"Jane","age":25,"city":"Boston"}';
const parsed = JSON.parse(jsonData);
console.log('Parsed object:', parsed);
console.log('Name:', parsed.name);
console.log('Age:', parsed.age);
console.log('Type of age:', typeof parsed.age);
/**
* ========================================
* EXAMPLE 7: Reviver Function
* ========================================
*/
console.log('\n--- Example 7: Reviver Function ---');
const eventJson = `{
"title": "Conference",
"startDate": "2024-12-15T09:00:00.000Z",
"endDate": "2024-12-15T17:00:00.000Z",
"attendees": 150
}`;
// Parse with date revival
const event = JSON.parse(eventJson, (key, value) => {
// Check if value looks like an ISO date
if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
return new Date(value);
}
return value;
});
console.log('Event:', event);
console.log('Start date is Date:', event.startDate instanceof Date);
console.log('Event date:', event.startDate.toLocaleDateString());
/**
* ========================================
* EXAMPLE 8: Safe JSON Parsing
* ========================================
*/
console.log('\n--- Example 8: Safe JSON Parsing ---');
function safeJSONParse(text, fallback = null) {
if (typeof text !== 'string') {
console.warn('Input is not a string');
return fallback;
}
try {
return JSON.parse(text);
} catch (error) {
console.warn('JSON parse error:', error.message);
return fallback;
}
}
console.log('Valid JSON:', safeJSONParse('{"valid": true}'));
console.log('Invalid JSON:', safeJSONParse('not json'));
console.log('Invalid with fallback:', safeJSONParse('broken', { error: true }));
console.log('Number input:', safeJSONParse(42));
/**
* ========================================
* EXAMPLE 9: Handling Dates
* ========================================
*/
console.log('\n--- Example 9: Handling Dates ---');
const appointment = {
title: 'Doctor Visit',
date: new Date('2024-12-20T10:30:00'),
reminder: new Date('2024-12-19T10:30:00'),
};
// Stringify (dates become ISO strings)
const appointmentJson = JSON.stringify(appointment);
console.log('Stringified:', appointmentJson);
// Parse without reviver (dates are strings)
const parsed1 = JSON.parse(appointmentJson);
console.log('Without reviver:');
console.log(' date type:', typeof parsed1.date);
console.log(' date value:', parsed1.date);
// Parse with date reviver
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
const parsed2 = JSON.parse(appointmentJson, (key, value) => {
if (typeof value === 'string' && ISO_DATE_REGEX.test(value)) {
return new Date(value);
}
return value;
});
console.log('With reviver:');
console.log(' date type:', typeof parsed2.date, parsed2.date instanceof Date);
console.log(' date value:', parsed2.date.toLocaleString());
/**
* ========================================
* EXAMPLE 10: Handling Maps and Sets
* ========================================
*/
console.log('\n--- Example 10: Handling Maps and Sets ---');
// Problem: Maps and Sets don't serialize properly
const dataWithCollections = {
name: 'Example',
myMap: new Map([
['key1', 'value1'],
['key2', 'value2'],
]),
mySet: new Set([1, 2, 3, 4, 5]),
};
console.log('Default stringify (loses data):');
console.log(JSON.stringify(dataWithCollections, null, 2));
// Solution: Custom serialization
function stringify(obj) {
return JSON.stringify(
obj,
(key, value) => {
if (value instanceof Map) {
return {
__type__: 'Map',
__data__: Array.from(value.entries()),
};
}
if (value instanceof Set) {
return {
__type__: 'Set',
__data__: Array.from(value),
};
}
return value;
},
2
);
}
function parse(json) {
return JSON.parse(json, (key, value) => {
if (value && typeof value === 'object') {
if (value.__type__ === 'Map') {
return new Map(value.__data__);
}
if (value.__type__ === 'Set') {
return new Set(value.__data__);
}
}
return value;
});
}
const serialized = stringify(dataWithCollections);
console.log('\nCustom stringify:');
console.log(serialized);
const restored = parse(serialized);
console.log('\nRestored:');
console.log('Map get key1:', restored.myMap.get('key1'));
console.log('Set has 3:', restored.mySet.has(3));
/**
* ========================================
* EXAMPLE 11: Circular References
* ========================================
*/
console.log('\n--- Example 11: Circular References ---');
const person = {
name: 'Alice',
friends: [],
};
const friend = {
name: 'Bob',
friends: [person], // Reference to person
};
person.friends.push(friend); // Circular: person -> friend -> person
// This would throw: "Converting circular structure to JSON"
try {
JSON.stringify(person);
} catch (e) {
console.log('Error:', e.message);
}
// Solution: Track seen objects
function stringifyCircular(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('\nWith circular handling:');
console.log(stringifyCircular(person));
/**
* ========================================
* EXAMPLE 12: Deep Clone with JSON
* ========================================
*/
console.log('\n--- Example 12: Deep Clone with JSON ---');
const original = {
name: 'Original',
nested: {
value: 42,
array: [1, 2, 3],
},
};
// Deep clone
const clone = JSON.parse(JSON.stringify(original));
// Modify clone
clone.name = 'Clone';
clone.nested.value = 100;
clone.nested.array.push(4);
console.log('Original:', JSON.stringify(original, null, 2));
console.log('Clone:', JSON.stringify(clone, null, 2));
console.log('Original unchanged:', original.nested.value === 42);
/**
* ========================================
* EXAMPLE 13: Limitations of JSON Clone
* ========================================
*/
console.log('\n--- Example 13: Limitations of JSON Clone ---');
const problematic = {
date: new Date(),
regex: /pattern/gi,
func: function () {
return 'hello';
},
undef: undefined,
symbol: Symbol('id'),
nan: NaN,
infinity: Infinity,
map: new Map([['a', 1]]),
set: new Set([1, 2, 3]),
};
console.log('Original:');
console.log(' date:', problematic.date);
console.log(' regex:', problematic.regex);
console.log(' func:', typeof problematic.func);
console.log(' undef:', problematic.undef);
console.log(' nan:', problematic.nan);
console.log(' infinity:', problematic.infinity);
const cloned = JSON.parse(JSON.stringify(problematic));
console.log('\nAfter JSON clone:');
console.log(' date:', cloned.date, '(type:', typeof cloned.date + ')');
console.log(' regex:', cloned.regex, '(type:', typeof cloned.regex + ')');
console.log(' func:', cloned.func, '(lost!)');
console.log(' undef:', cloned.undef, '(lost!)');
console.log(' nan:', cloned.nan, '(became null)');
console.log(' infinity:', cloned.infinity, '(became null)');
console.log(' map:', cloned.map, '(became empty object)');
console.log(' set:', cloned.set, '(became empty object)');
/**
* ========================================
* EXAMPLE 14: structuredClone
* ========================================
*/
console.log('\n--- Example 14: structuredClone ---');
const withSpecialTypes = {
date: new Date(),
regex: /pattern/gi,
array: [1, 2, 3],
nested: { deep: { value: 42 } },
map: new Map([['key', 'value']]),
set: new Set([1, 2, 3]),
};
// Modern deep clone
const structuredCopy = structuredClone(withSpecialTypes);
console.log('Date preserved:', structuredCopy.date instanceof Date);
console.log('Regex preserved:', structuredCopy.regex instanceof RegExp);
console.log('Map preserved:', structuredCopy.map instanceof Map);
console.log('Set preserved:', structuredCopy.set instanceof Set);
// Verify independence
structuredCopy.nested.deep.value = 100;
console.log(
'Original value unchanged:',
withSpecialTypes.nested.deep.value === 42
);
/**
* ========================================
* EXAMPLE 15: Custom Deep Clone
* ========================================
*/
console.log('\n--- Example 15: Custom Deep Clone ---');
function deepClone(obj, seen = new WeakMap()) {
// Handle primitives and null
if (obj === null || typeof obj !== 'object') {
return obj;
}
// Handle circular references
if (seen.has(obj)) {
return seen.get(obj);
}
// Handle Date
if (obj instanceof Date) {
return new Date(obj.getTime());
}
// Handle RegExp
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags);
}
// Handle Map
if (obj instanceof Map) {
const clone = new Map();
seen.set(obj, clone);
obj.forEach((value, key) => {
clone.set(deepClone(key, seen), deepClone(value, seen));
});
return clone;
}
// Handle Set
if (obj instanceof Set) {
const clone = new Set();
seen.set(obj, clone);
obj.forEach((value) => {
clone.add(deepClone(value, seen));
});
return clone;
}
// Handle Array
if (Array.isArray(obj)) {
const clone = [];
seen.set(obj, clone);
for (let i = 0; i < obj.length; i++) {
clone[i] = deepClone(obj[i], seen);
}
return clone;
}
// Handle Object
const clone = Object.create(Object.getPrototypeOf(obj));
seen.set(obj, clone);
for (const key of Reflect.ownKeys(obj)) {
const descriptor = Object.getOwnPropertyDescriptor(obj, key);
if (descriptor.value !== undefined) {
descriptor.value = deepClone(descriptor.value, seen);
}
Object.defineProperty(clone, key, descriptor);
}
return clone;
}
// Test with circular reference
const objWithCircular = { name: 'Test' };
objWithCircular.self = objWithCircular;
objWithCircular.date = new Date();
objWithCircular.map = new Map([['a', 1]]);
const clonedObj = deepClone(objWithCircular);
console.log('Cloned with circular:', clonedObj.self === clonedObj); // true
console.log('Date cloned:', clonedObj.date instanceof Date);
console.log('Map cloned:', clonedObj.map instanceof Map);
/**
* ========================================
* EXAMPLE 16: JSON Validation
* ========================================
*/
console.log('\n--- Example 16: JSON Validation ---');
function validateJSON(data, schema) {
const errors = [];
for (const [key, rules] of Object.entries(schema)) {
const value = data[key];
// Required check
if (rules.required && (value === undefined || value === null)) {
errors.push(`${key} is required`);
continue;
}
if (value === undefined || value === null) continue;
// Type check
if (rules.type) {
const actualType = Array.isArray(value) ? 'array' : typeof value;
if (actualType !== rules.type) {
errors.push(`${key} must be type ${rules.type}, got ${actualType}`);
}
}
// Number constraints
if (typeof value === 'number') {
if (rules.min !== undefined && value < rules.min) {
errors.push(`${key} must be >= ${rules.min}`);
}
if (rules.max !== undefined && value > rules.max) {
errors.push(`${key} must be <= ${rules.max}`);
}
}
// String constraints
if (typeof value === 'string') {
if (rules.minLength && value.length < rules.minLength) {
errors.push(`${key} must be at least ${rules.minLength} characters`);
}
if (rules.maxLength && value.length > rules.maxLength) {
errors.push(`${key} must be at most ${rules.maxLength} characters`);
}
if (rules.pattern && !rules.pattern.test(value)) {
errors.push(`${key} has invalid format`);
}
}
// Array constraints
if (Array.isArray(value)) {
if (rules.minItems && value.length < rules.minItems) {
errors.push(`${key} must have at least ${rules.minItems} items`);
}
if (rules.maxItems && value.length > rules.maxItems) {
errors.push(`${key} must have at most ${rules.maxItems} items`);
}
}
}
return {
valid: errors.length === 0,
errors,
};
}
const userSchema = {
name: { required: true, type: 'string', minLength: 2, maxLength: 50 },
email: {
required: true,
type: 'string',
pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
},
age: { required: false, type: 'number', min: 0, max: 150 },
tags: { required: false, type: 'array', minItems: 1, maxItems: 10 },
};
const validUser = { name: 'John Doe', email: 'john@example.com', age: 30 };
const invalidUser = { name: 'J', email: 'invalid', age: 200 };
console.log('Valid user:', validateJSON(validUser, userSchema));
console.log('Invalid user:', validateJSON(invalidUser, userSchema));
/**
* ========================================
* EXAMPLE 17: JSON Diff
* ========================================
*/
console.log('\n--- Example 17: JSON Diff ---');
function jsonDiff(obj1, obj2, path = '') {
const differences = [];
// Get all keys from both objects
const allKeys = new Set([
...Object.keys(obj1 || {}),
...Object.keys(obj2 || {}),
]);
for (const key of allKeys) {
const fullPath = path ? `${path}.${key}` : key;
const val1 = obj1?.[key];
const val2 = obj2?.[key];
// Check if key was added
if (val1 === undefined && val2 !== undefined) {
differences.push({ type: 'added', path: fullPath, value: val2 });
continue;
}
// Check if key was removed
if (val1 !== undefined && val2 === undefined) {
differences.push({ type: 'removed', path: fullPath, value: val1 });
continue;
}
// Check if types are different
const type1 = Array.isArray(val1) ? 'array' : typeof val1;
const type2 = Array.isArray(val2) ? 'array' : typeof val2;
if (type1 !== type2) {
differences.push({
type: 'changed',
path: fullPath,
from: val1,
to: val2,
});
continue;
}
// Recursively check objects
if (type1 === 'object' && val1 !== null) {
differences.push(...jsonDiff(val1, val2, fullPath));
continue;
}
// Check primitive values
if (val1 !== val2) {
differences.push({
type: 'changed',
path: fullPath,
from: val1,
to: val2,
});
}
}
return differences;
}
const before = {
name: 'John',
age: 30,
address: { city: 'NYC', zip: '10001' },
hobbies: ['reading'],
};
const after = {
name: 'John',
age: 31,
address: { city: 'Boston', zip: '02101' },
email: 'john@example.com',
};
console.log('Differences:');
jsonDiff(before, after).forEach((diff) => {
if (diff.type === 'added') {
console.log(` + ${diff.path}: ${JSON.stringify(diff.value)}`);
} else if (diff.type === 'removed') {
console.log(` - ${diff.path}: ${JSON.stringify(diff.value)}`);
} else {
console.log(
` ~ ${diff.path}: ${JSON.stringify(diff.from)} → ${JSON.stringify(
diff.to
)}`
);
}
});
/**
* ========================================
* Summary
* ========================================
*/
console.log('\n========================================');
console.log('Working with JSON - Examples Complete');
console.log('========================================');
console.log('Key functions demonstrated:');
console.log('- JSON.stringify() with replacer and spacing');
console.log('- JSON.parse() with reviver');
console.log('- toJSON() for custom serialization');
console.log('- Handling dates, Maps, Sets');
console.log('- Circular reference handling');
console.log('- Deep cloning techniques');
console.log('- JSON validation and diffing');