Skip to content

JavaScript JSON

JSON (JavaScript Object Notation) is a lightweight data interchange format that is easy for humans to read and write, and easy for machines to parse and generate. JSON is widely used in modern web development for data transmission between clients and servers.

What is JSON

JSON is a text-based data interchange format based on JavaScript object literal syntax but independent of JavaScript. Key features:

  1. Lightweight: More concise than XML
  2. Human Readable: Text format that's easy to read
  3. Wide Support: Almost all programming languages have JSON libraries
  4. Structured: Supports complex data structures
javascript
// JSON object example
const jsonString = `{
    "name": "John",
    "age": 25,
    "isStudent": true,
    "hobbies": ["reading", "swimming", "coding"],
    "address": {
        "city": "New York",
        "street": "123 Main St"
    }
}`;

console.log(typeof jsonString); // "string"

JSON Syntax Rules

Basic Syntax

javascript
// Valid JSON format
const validJson = `{
    "name": "John",
    "age": 25,
    "isActive": true,
    "salary": null,
    "hobbies": ["reading", "swimming"],
    "address": {
        "city": "New York",
        "zipcode": "10001"
    }
}`;

// Invalid JSON (JavaScript object literal)
// Keys must use double quotes
// Single quotes not allowed
// undefined and functions not valid

JSON Data Types

javascript
// String
const jsonString = `"Hello World"`;

// Number
const jsonNumber = `42`;
const jsonFloat = `3.14159`;

// Boolean
const jsonBoolean = `true`;

// null
const jsonNull = `null`;

// Object
const jsonObject = `{ "name": "John", "age": 25 }`;

// Array
const jsonArray = `["apple", "banana", "orange"]`;

// Nested structure
const complexJson = `{
    "users": [
        { "id": 1, "name": "John" },
        { "id": 2, "name": "Jane" }
    ],
    "total": 2
}`;

JSON Object Methods

JSON.parse() - Parse JSON String

javascript
// Basic parsing
const jsonString = `{ "name": "John", "age": 25, "isStudent": true }`;
const obj = JSON.parse(jsonString);
console.log(obj.name);      // "John"
console.log(obj.age);       // 25
console.log(obj.isStudent); // true

// Parse array
const jsonArray = `["apple", "banana", "orange"]`;
const fruits = JSON.parse(jsonArray);
console.log(fruits[0]); // "apple"

// With reviver parameter
const userData = `{ "name": "John", "birthDate": "1990-01-01", "salary": "5000" }`;
const parsedUser = JSON.parse(userData, (key, value) => {
    if (key === "birthDate") {
        return new Date(value);
    }
    if (key === "salary") {
        return Number(value);
    }
    return value;
});

console.log(parsedUser.birthDate instanceof Date); // true
console.log(typeof parsedUser.salary);             // "number"

JSON.stringify() - Serialize to JSON String

javascript
// Basic serialization
const obj = { name: "John", age: 25, isStudent: true };
const jsonString = JSON.stringify(obj);
console.log(jsonString); // {"name":"John","age":25,"isStudent":true}

// With replacer parameter (filter properties)
const user = {
    name: "John",
    age: 25,
    password: "secret123",
    email: "john@example.com"
};

// Only serialize specified properties
const publicData = JSON.stringify(user, ["name", "age", "email"]);
console.log(publicData); // {"name":"John","age":25,"email":"john@example.com"}

// Use function replacer
const filteredData = JSON.stringify(user, (key, value) => {
    if (key === "password") {
        return undefined; // Exclude password
    }
    return value;
});

// Formatted output
const formattedJson = JSON.stringify(obj, null, 2);
console.log(formattedJson);
/*
{
  "name": "John",
  "age": 25,
  "isStudent": true
}
*/

toJSON() Method

Objects can define toJSON() to customize serialization:

javascript
class User {
    constructor(name, birthDate) {
        this.name = name;
        this.birthDate = birthDate;
    }
    
    toJSON() {
        return {
            name: this.name,
            age: this.getAge(),
            birthDate: this.birthDate.toISOString().split("T")[0]
        };
    }
    
    getAge() {
        const today = new Date();
        const birth = new Date(this.birthDate);
        return today.getFullYear() - birth.getFullYear();
    }
}

const user = new User("John", new Date("1990-01-01"));
console.log(JSON.stringify(user)); // {"name":"John","age":34,"birthDate":"1990-01-01"}

JSON Limitations

Unsupported Types

javascript
const obj = {
    func: function() { return "hello"; },  // Functions
    undef: undefined,                       // undefined
    sym: Symbol("id"),                      // Symbol
    date: new Date(),                       // Date object
    regex: /abc/g                           // RegExp
};

const json = JSON.stringify(obj);
console.log(json); // {"date":"2024-01-01T00:00:00.000Z"}
// Functions, undefined, Symbol are ignored; Date converted to string

Circular Reference

javascript
const obj = { name: "John" };
obj.self = obj; // Circular reference

try {
    const json = JSON.stringify(obj);
} catch (error) {
    console.log("Serialization error:", error.message);
    // "Converting circular structure to JSON"
}

// 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]";
            }
            seen.add(value);
        }
        return value;
    });
}

Deep Copy with JSON

javascript
// Deep copy using JSON (has limitations)
const original = {
    name: "John",
    age: 25,
    hobbies: ["reading", "swimming"],
    address: { city: "New York", street: "Main St" }
};

const copy = JSON.parse(JSON.stringify(original));
copy.name = "Jane";
copy.hobbies.push("coding");

console.log(original.name);    // "John" (unchanged)
console.log(original.hobbies); // ["reading", "swimming"] (unchanged)

// Limitation: Functions and Dates are lost
const objWithFunc = {
    name: "John",
    greet: function() { return "Hello"; },
    date: new Date()
};

const jsonCopy = JSON.parse(JSON.stringify(objWithFunc));
console.log(jsonCopy.greet); // undefined (function lost)
console.log(jsonCopy.date instanceof Date); // false (becomes string)

Web Development Applications

AJAX Data Transmission

javascript
// Send JSON data
async function sendUserData(userData) {
    try {
        const response = await fetch("/api/users", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(userData)
        });
        
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
        }
        
        return await response.json();
    } catch (error) {
        console.error("Failed to send data:", error);
        throw error;
    }
}

// Receive JSON data
async function fetchUsers() {
    try {
        const response = await fetch("/api/users");
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        return await response.json();
    } catch (error) {
        console.error("Failed to fetch users:", error);
        throw error;
    }
}

Local Storage

javascript
// Storage manager for complex objects
class StorageManager {
    static save(key, data) {
        try {
            localStorage.setItem(key, JSON.stringify(data));
            return true;
        } catch (error) {
            console.error("Failed to save:", error);
            return false;
        }
    }
    
    static load(key) {
        try {
            const jsonString = localStorage.getItem(key);
            if (jsonString === null) return null;
            return JSON.parse(jsonString);
        } catch (error) {
            console.error("Failed to load:", error);
            return null;
        }
    }
    
    static remove(key) {
        localStorage.removeItem(key);
    }
}

// Usage
const preferences = { theme: "dark", language: "en-US", notifications: true };
StorageManager.save("userPreferences", preferences);
const loaded = StorageManager.load("userPreferences");
console.log(loaded); // { theme: "dark", language: "en-US", notifications: true }

Best Practices

1. Error Handling

javascript
// Safe JSON parse
function safeJsonParse(str, defaultValue = null) {
    try {
        return JSON.parse(str);
    } catch (error) {
        console.warn("JSON parse failed:", error.message);
        return defaultValue;
    }
}

// Safe JSON stringify
function safeJsonStringify(obj, defaultValue = "{}") {
    try {
        return JSON.stringify(obj);
    } catch (error) {
        console.warn("JSON stringify failed:", error.message);
        return defaultValue;
    }
}

// Usage
const invalidJson = '{"name":"John",}'; // Invalid
const parsed = safeJsonParse(invalidJson, {});
console.log(parsed); // {}

2. Data Validation

javascript
// Simple JSON Schema validation
class JsonValidator {
    static validate(data, schema) {
        const errors = [];
        
        for (const [key, rules] of Object.entries(schema)) {
            const value = data[key];
            
            // Required validation
            if (rules.required && (value === undefined || value === null)) {
                errors.push(`Field "${key}" is required`);
                continue;
            }
            
            if (value !== undefined) {
                // Type validation
                if (rules.type && typeof value !== rules.type) {
                    errors.push(`Field "${key}" should be ${rules.type}`);
                }
                
                // String validation
                if (typeof value === "string") {
                    if (rules.minLength && value.length < rules.minLength) {
                        errors.push(`Field "${key}" min length is ${rules.minLength}`);
                    }
                    if (rules.maxLength && value.length > rules.maxLength) {
                        errors.push(`Field "${key}" max length is ${rules.maxLength}`);
                    }
                }
                
                // Number validation
                if (typeof value === "number") {
                    if (rules.min !== undefined && value < rules.min) {
                        errors.push(`Field "${key}" min value is ${rules.min}`);
                    }
                    if (rules.max !== undefined && value > rules.max) {
                        errors.push(`Field "${key}" max value is ${rules.max}`);
                    }
                }
            }
        }
        
        return { valid: errors.length === 0, errors };
    }
}

// Usage
const userData = { name: "John", age: 25, email: "john@example.com" };
const userSchema = {
    name: { required: true, type: "string", minLength: 2 },
    age: { required: true, type: "number", min: 0, max: 150 },
    email: { required: true, type: "string" }
};

const validation = JsonValidator.validate(userData, userSchema);
console.log("Validation result:", validation);

3. Configuration Manager

javascript
class ConfigManager {
    constructor() {
        this.config = this.loadDefaultConfig();
        this.loadStoredConfig();
    }
    
    loadDefaultConfig() {
        return {
            apiUrl: "https://api.example.com",
            timeout: 5000,
            retries: 3,
            debug: false
        };
    }
    
    loadStoredConfig() {
        const stored = localStorage.getItem("appConfig");
        if (stored) {
            try {
                const parsed = JSON.parse(stored);
                this.config = { ...this.config, ...parsed };
            } catch (error) {
                console.error("Failed to load config:", error);
            }
        }
    }
    
    getConfig(key = null) {
        return key ? this.config[key] : this.config;
    }
    
    setConfig(key, value) {
        this.config[key] = value;
        this.saveConfig();
    }
    
    saveConfig() {
        try {
            localStorage.setItem("appConfig", JSON.stringify(this.config));
        } catch (error) {
            console.error("Failed to save config:", error);
        }
    }
    
    resetConfig() {
        this.config = this.loadDefaultConfig();
        localStorage.removeItem("appConfig");
    }
}

// Usage
const config = new ConfigManager();
console.log(config.getConfig("apiUrl")); // "https://api.example.com"
config.setConfig("debug", true);

Summary

Key points about JavaScript JSON:

  1. Basic Concept: Lightweight data interchange format based on JS object syntax
  2. Syntax Rules: Strict key-value format, keys must use double quotes
  3. Core Methods: JSON.parse() for parsing, JSON.stringify() for serialization
  4. Data Types: Supports strings, numbers, booleans, null, objects, arrays
  5. Limitations: No functions, undefined, Symbol, or circular references
  6. Custom Handling: toJSON() method, replacer and reviver parameters
  7. Applications: AJAX data transmission, local storage, configuration files
  8. Best Practices: Error handling, performance optimization, data validation

Mastering JSON handling is fundamental for web development. In the next chapter, we will learn about JavaScript async programming.

Content is for learning and research only.