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