JSON and JSON Methods

Learn how to work with JSON in JavaScript using JSON.stringify() and JSON.parse(). Understand JSON syntax, limitations, real-world use cases, common mistakes.

Loading...
JSON and JSON Methods

JSON stands for JavaScript Object Notation. It's a lightweight, text-based format used to store and exchange data.

It's easy for humans to read and write, and easy for machines to parse and generate.

JSON is widely used when working with APIs, including when using Promises, async/await, and the Fetch API, so understanding it now will help you later.

JSON Syntax Rules

JSON follows strict formatting rules:

  • Data is in name/value pairs (similar to JavaScript objects)
  • Data is separated by commas
  • Curly braces {} hold objects
  • Square brackets [] hold arrays
  • Strings must be in double quotes "" (not single quotes)
  • No trailing commas allowed
  • No comments allowed
  • No functions or undefined values

Valid JSON Data Types

JSON supports these data types:

  • String: Text data enclosed in double quotes (")

    "Hello World"
    "JavaScript"
    ""
  • Number: Both integers and floating-point numbers (no NaN, Infinity, or hex)

    42
    3.14159
    -17
    0
  • Boolean: Represents true/false values

    true
    false
  • null: Represents an empty or unknown value

    null
  • Object: A collection of key-value pairs. Keys must be strings.

    {
      "name": "John",
      "age": 30,
      "isStudent": false
    }
  • Array: An ordered list of values, which can include any JSON type

    [1, 2, 3, 4, 5]
    ["apple", "banana", "orange"]
    [true, false, null]

JSON vs JavaScript Objects

JSON looks like JavaScript objects but has stricter rules.

Feature JavaScript Object JSON
Syntax { name: "John" } { "name": "John" }
Quotes on keys Optional (single/double) Required double quotes
Strings Single or double quotes Double quotes only
Functions Allowed Not allowed
undefined Allowed Not allowed
Comments Allowed Not allowed
Trailing commas Allowed Not allowed

JSON is more strict and is meant for data only, not behavior (no functions, no comments, etc.).


JSON Methods in JavaScript

JavaScript provides two essential built-in methods for working with JSON:

JSON.stringify()

JSON.stringify() converts a JavaScript value (object, array, number, string, etc.) into a JSON-formatted string.

Use JSON.stringify() when:

  • Sending data to a server
  • Saving data in localStorage
  • Debugging

Syntax:

JSON.stringify(value, replacer, space);
  • value: The data you want to convert
  • replacer: (optional) Filter or format the data
  • space: (optional) Add indentation (for readability)

Basic Examples:

Converting an object to JSON string:

const user = {
  name: "Alice",
  age: 25,
  isEmployed: true,
};
 
const jsonString = JSON.stringify(user);
console.log(jsonString); // Output: {"name":"Alice","age":25,"isEmployed":true}

Converting an array to JSON string:

const fruits = ["apple", "banana", "orange"];
const jsonArray = JSON.stringify(fruits);
console.log(jsonArray); // Output: ["apple","banana","orange"]

Converting primitive values:

console.log(JSON.stringify(42)); // "42"
console.log(JSON.stringify("Hello")); // "\"Hello\""
console.log(JSON.stringify(true)); // "true"
console.log(JSON.stringify(null)); // "null"

Pretty Print JSON:

Add indentation for easier reading (helpful in logs, config files, etc.):

const apiResponse = {
  status: "success",
  data: {
    users: [
      { id: 1, name: "John" },
      { id: 2, name: "Jane" },
    ],
  },
  timestamp: "2024-01-15T10:30:00Z",
};
 
// Pretty print with 2 spaces indentation
const prettyJson = JSON.stringify(apiResponse, null, 2);
console.log(prettyJson);

Output:

{
  "status": "success",
  "data": {
    "users": [
      {
        "id": 1,
        "name": "John"
      },
      {
        "id": 2,
        "name": "Jane"
      }
    ]
  },
  "timestamp": "2024-01-15T10:30:00Z"
}

Using the replacer Function in JSON.stringify()

The replacer parameter in JSON.stringify(value, replacer, space) lets you control which values get included or how they are transformed.

  • It can be an array specifying keys to include.
  • Or a function called for each key-value pair, allowing you to filter or modify values.

Example:

const data = {
  name: "Alice",
  age: null,
  city: "New York",
};
 
const jsonString = JSON.stringify(data, (key, value) => {
  if (value === null) {
    return undefined; // skip this property
  }
  return value;
});
 
console.log(jsonString); // Output: {"name":"Alice","city":"New York"}

You can use the replacer function when you want to customize the JSON output, for example, to exclude sensitive data or simplify complex objects.

JSON.parse()

JSON.parse() converts a JSON string into a JavaScript value (object, array, number, string, etc.).

This is essential when:

  • Receiving data from a server (APIs)
  • Reading data from localStorage, files, or databases

Syntax:

JSON.parse(text, reviver);
  • text: A valid JSON string
  • reviver: (optional) A function to transform the result

Basic Examples:

Parsing a JSON string to object (typical API response):

const serverResponse =
  '{"status":"success","userId":123,"message":"Login successful"}';
const responseObject = JSON.parse(serverResponse);
console.log(responseObject); // Output: {status: "success", userId: 123, message: "Login successful"}

Parsing a JSON array:

const jsonArray = '["red", "green", "blue"]';
const colorsArray = JSON.parse(jsonArray);
console.log(colorsArray); // Output: ["red", "green", "blue"]

Parsing primitive values:

console.log(JSON.parse("42")); // 42
console.log(JSON.parse('"Hello"')); // "Hello"
console.log(JSON.parse("true")); // true
console.log(JSON.parse("null")); // null

Using the reviver Function in JSON.parse()

The reviver is an optional function you can pass to JSON.parse() to customize how values are transformed during parsing.

It takes two arguments, key and value and returns the transformed value.

Example:

const json = `{
  "name": "Alice",
  "joined": "2025-07-15T04:00:00.000Z"
}`;
 
const parsed = JSON.parse(json, (key, value) => {
  if (key === "joined") {
    return new Date(value); // Convert ISO string to Date
  }
  return value;
});
 
console.log(parsed.joined instanceof Date); // true
console.log(parsed.joined.getFullYear()); // 2025

Here,

  • The JSON string includes a date as a string ("2025-07-15T04:00:00.000Z").
  • The reviver function checks each key during parsing.
  • If the key is "joined", it converts the string into a real JavaScript Date object.
  • Otherwise, it leaves the value as is.

You can use the reviver to sanitize, convert, or reject values as needed. It's especially useful when working with structured API responses.


Simulating API Communication

This example shows how JSON is used to send and receive data when communicating with a server.

const userData = {
  username: "john_doe",
  email: "john@example.com",
  preferences: {
    theme: "dark",
    notifications: true,
  },
};
 
// Convert to JSON for sending (this will happen automatically with fetch)
const jsonData = JSON.stringify(userData);
console.log("Data being sent to server:", jsonData);
 
// Simulating received data from server
const serverResponse =
  '{"status":"success","userId":123,"token":"abc123xyz","message":"User created successfully"}';
 
// Parse the response (this will happen automatically with fetch)
const parsedResponse = JSON.parse(serverResponse);
console.log("Received from server:", parsedResponse);
 
// Now you can use the parsed data
if (parsedResponse.status === "success") {
  console.log(`User created with ID: ${parsedResponse.userId}`);
  // Store the token for future API calls
  console.log(`Auth token: ${parsedResponse.token}`);
}
  • userData object contains user information like username, email, and preferences.
  • Converting the object to JSON:
    • const jsonData = JSON.stringify(userData); this turns the JavaScript object into a JSON string, a format suitable for sending over the network. When you use fetch() or other APIs to send data, this conversion happens automatically.
  • Logging the JSON string:
    • console.log("Data being sent to server:", jsonData); you see the string version of the data, ready to be sent.
  • Simulating a server response:
    • The serverResponse variable holds a JSON string, what a server might send back after processing the request.
  • Parsing the JSON response back into an object:
    • const parsedResponse = JSON.parse(serverResponse); converts the JSON string from the server into a JavaScript object you can use in your code.
  • Logging the parsed response:
    • console.log("Received from server:", parsedResponse); you see the server’s response as an object with properties like status, userId, token, and message.
  • Using the parsed data:
    • The code checks if the status is "success" and then accesses values from the response to:
      • Show the new user's ID
      • Display the authentication token

Why this matters?

  • Data sent to servers must be in string format (usually JSON).
  • Data received from servers is also in JSON string format and must be parsed to work with it in JavaScript.
  • JSON.stringify() and JSON.parse() are essential for this communication.
  • This example helps you understand the typical flow of data in web applications, preparing you for working with APIs and asynchronous JavaScript.

Error Handling with JSON

When working with JSON, errors can happen, especially when parsing data from external sources like APIs. It’s important to handle these errors so your program doesn’t crash.

Handling JSON.stringify() Errors

Sometimes JSON.stringify() can fail, for example, if the object contains circular references.

const obj = { name: "John" };
obj.self = obj; // Circular reference causes error
 
function safeStringify(data) {
  try {
    return JSON.stringify(data);
  } catch {
    console.error("Error: Unable to convert object to JSON.");
    return null;
  }
}
 
const json = safeStringify(obj);
console.log(json); // null, Error: Unable to convert object to JSON.

Here,

  • You create an object obj with a property name.
  • Then, obj.self = obj; creates a circular reference (object refers to itself).
  • Calling JSON.stringify(obj) on this will throw an error because JSON cannot represent circular references.
  • safeStringify() wraps JSON.stringify() inside a try...catch to catch this error.
  • If an error happens, it logs a friendly error message and returns null instead of crashing.
  • Finally, when you call safeStringify(obj), it returns null and prints the error.

Handling JSON.parse() Errors

Parsing JSON strings can also fail if the data is not valid JSON.

const invalidJson = '{"name": "John", age: 30}'; // Invalid JSON (unquoted key)
 
function safeParse(json) {
  try {
    return JSON.parse(json);
  } catch {
    console.error("Error: Invalid JSON string.");
    return null;
  }
}
 
const data = safeParse(invalidJson);
console.log(data); // null because parsing failed
 
const validJson = '{"name": "John", "age": 30}';
console.log(safeParse(validJson)); // { name: "John", age: 30 }

Here,

  • You define a JSON string invalidJson that has an error: the key age is not quoted, which is invalid JSON syntax.
  • safeParse() tries to parse the string with JSON.parse() inside a try...catch.
  • When parsing fails due to invalid syntax, it catches the error, logs a message, and returns null.
  • The first call safeParse(invalidJson) returns null because parsing failed.
  • Then, you test safeParse() with validJson, a correctly formatted JSON string.
  • This time, parsing succeeds and returns a JavaScript object.

What JSON Cannot Handle

JSON is great for exchanging data, but it has limitations. Some JavaScript values cannot be stored or are transformed when converting to JSON.

const complexObject = {
  // These will be preserved
  name: "John",
  age: 30,
  hobbies: ["reading", "coding"],
  address: {
    city: "New York",
    zipCode: 10001,
  },
  isActive: true,
  lastLogin: null,
 
  // These will be lost or changed
  greet: function () {
    return "Hello!";
  }, // Functions are ignored
  undefinedValue: undefined, // undefined is ignored
  symbolValue: Symbol("test"), // Symbols are ignored
  dateValue: new Date(), // Converted to string (ISO format)
  regexValue: /test/g, // Becomes empty object {}
  infinityValue: Infinity, // Converted to null
  nanValue: NaN, // Converted to null
};
 
console.log("Original object:", complexObject);
console.log("JSON string:", JSON.stringify(complexObject, null, 2));
console.log("Parsed back:", JSON.parse(JSON.stringify(complexObject)));

What Happens When You Use JSON.stringify()?

  • Preserved values:
    • Strings, numbers, booleans, null
    • Objects and arrays
  • Lost or transformed values:
    • Functions: Removed entirely (not saved)
    • undefined: Removed (not saved)
    • Symbols: Removed (not saved)
    • Date objects: Converted to ISO date strings like "2025-07-15T10:30:00.000Z"
    • Regular expressions: Become empty objects ({})
    • Special numbers (Infinity, NaN): Converted to null

Why Does This Matter?

When sending or storing data as JSON, any unsupported values will not survive the conversion correctly. This can lead to missing data or unexpected results when you parse the JSON back into JavaScript.

Handling Dates Properly

JSON can’t store JavaScript Date objects directly, so you need to convert dates to strings first.

const dataWithDate = {
  user: "John",
  createdAt: new Date().toISOString(), // Convert to string
  updatedAt: new Date().toISOString(),
};
 
const jsonString = JSON.stringify(dataWithDate);
const parsed = JSON.parse(jsonString);
 
// Convert ISO strings back to Date objects if needed
parsed.createdAt = new Date(parsed.createdAt);
parsed.updatedAt = new Date(parsed.updatedAt);
 
console.log("Data with dates handled correctly:", parsed);
  • Store dates as ISO strings before sending or saving.
  • Convert back to Date objects after parsing when you need date functionality.

This way, you keep your dates accurate and avoid issues with unsupported JSON types.


Common JSON Mistakes

When working with JSON, watch out for these common issues:

  • Functions and undefined values are lost: JSON cannot represent functions or undefined. These are removed during serialization (using JSON.stringify()).
  • Circular references cause errors: Objects that reference themselves cause JSON.stringify() to throw an error. Use custom logic or libraries like flatted to handle this.
  • Date objects become strings: Dates are converted to ISO strings. If you need Date objects after parsing, you must convert them back manually.
  • Special numeric values become null: Values like NaN, Infinity, and -Infinity become null when stringified.
  • Trailing commas or unquoted keys cause parsing errors: JSON syntax is strict. Even a trailing comma or missing quotes around keys breaks JSON.parse().
  • Large JSON blocks can block the main thread: Parsing very large JSON strings can freeze your app temporarily. Consider chunking or asynchronous parsing.

👉 Next tutorial: Callback Hell

Support my work!