Skillversitas

28. JSON (JavaScript Object Notation)

JSON is a lightweight, human-readable text-based data interchange format that is easy for machines to parse. JSON in JavaScript is a subset of object literals — but there are strict rules that must be followed.

Why Is JSON Important?

Almost all data communication on the web uses JSON: REST APIs, localStorage, configuration files, and so on. Mastering JSON is a must for web development.

// JavaScript object — any type allowed
const obj = {
  name: "Mike",
  age: 20,
  active: true,
  grade: null,
  hobbies: ["coding", "reading"],
  address: { city: "New York" },
  lahir: new Date() // ← Date, not JSON!
};

// JSON — only basic types
const json = JSON.stringify(obj);
// Date is automatically converted to an ISO string

Code Example

JSON.stringify() — Object to String

const student = {
  name: "Mike Johnson",
  studentId: "2024001",
  major: "Computer Science",
  gpa: 3.75,
  active: true,
  course: ["Algorithms", "Database", "Web Programming"],
  address: {
    city: "New York",
    province: "New York"
  }
};

// Basic
const jsonString = JSON.stringify(student);
console.log(typeof jsonString); // "string"
console.log(jsonString);
// '{"name":"Mike Johnson","studentId":"2024001",...}'

// Pretty print (with indentation)
const pretty = JSON.stringify(student, null, 2);
console.log(pretty);
// {
//   "name": "Mike Johnson",
//   "studentId": "2024001",
//   "major": "Computer Science",
//   ...
// }

// With a replacer — filter only the properties you want
const ringkas = JSON.stringify(student, ["name", "studentId", "gpa"]);
console.log(ringkas);
// '{"name":"Mike Johnson","studentId":"2024001","gpa":3.75}'

// With a replacer function
const filtered = JSON.stringify(student, (key, value) => {
  // Remove properties that start with an underscore (if any)
  if (key.startsWith("_")) return undefined;
  // Remove large fields
  if (key === "address") return undefined;
  return value;
}, 2);

JSON.parse() — String to Object

const jsonString = '{"name":"Mike","studentId":"2024001","gpa":3.75}';

// Basic
const object = JSON.parse(jsonString);
console.log(object.name); // "Mike"
console.log(object.gpa);  // 3.75

// With a reviver — transform values while parsing
const data = '{"name":"Mike","gpa":"3.75","date":"2026-07-14T00:00:00Z"}';

const objectReviver = JSON.parse(data, (key, value) => {
  // Convert the gpa string to a number
  if (key === "gpa") return parseFloat(value);
  // Convert the date string to a Date
  if (key === "date") return new Date(value);
  return value;
});

console.log(objectReviver.gpa);       // 3.75 (number)
console.log(objectReviver.date instanceof Date); // true

// Error handling
try {
  const invalid = JSON.parse("not json");
} catch (error) {
  console.error("Invalid JSON:", error.message);
}

Common JSON Patterns

// 1. Save data to localStorage
function saveData(name, data) {
  try {
    const json = JSON.stringify(data);
    localStorage.setItem(name, json);
    return true;
  } catch (error) {
    console.error("Failed to save:", error);
    return false;
  }
}

// 2. Load data from localStorage
function loadData(name) {
  try {
    const json = localStorage.getItem(name);
    if (json === null) return null;
    return JSON.parse(json);
  } catch (error) {
    console.error("Failed to load:", error);
    return null;
  }
}

// 3. Deep clone with JSON
const original = {
  name: "Mike",
  address: { city: "New York" },
  course: ["Algorithms"]
};

const clone = JSON.parse(JSON.stringify(original));
clone.address.city = "Chicago";
console.log(original.address.city); // "New York" (unchanged)

// 4. Convert between formats
const csvData = "name,studentId,gpa\nMike,2024001,3.75\nAnna,2024002,3.20";
const lines = csvData.split("\n").slice(1);
const studentArray = lines.map(line => {
  const [name, studentId, gpa] = line.split(",");
  return { name, studentId, gpa: parseFloat(gpa) };
});
console.log(JSON.stringify(studentArray, null, 2));

Common Mistakes with JSON

// 1. CANNOT parse functions
const obj = { name: "Mike", greet() { return "Hi"; } };
const json = JSON.stringify(obj);
console.log(json); // '{"name":"Mike"}' — the method is gone!
const back = JSON.parse(json);
console.log(back.greet); // undefined

// 2. CANNOT parse undefined
const data = { name: "Mike", age: undefined };
console.log(JSON.stringify(data)); // '{"name":"Mike"}' — undefined is removed

// 3. CANNOT parse Symbols
const obj2 = { id: Symbol("123") };
// JSON.stringify(obj2); // Error!

// 4. CANNOT parse Infinity/NaN
const obj3 = { grade: Infinity, score: NaN };
console.log(JSON.stringify(obj3)); // '{"grade":null,"score":null}'

// 5. Dates become strings, not Date objects
const obj4 = { time: new Date() };
const parsed = JSON.parse(JSON.stringify(obj4));
console.log(parsed.time instanceof Date); // false! (it's a string)

// Solution: use a reviver to convert dates
const withDate = JSON.parse(
  JSON.stringify(obj4),
  (key, value) => key === "time" ? new Date(value) : value
);
console.log(withDate.time instanceof Date); // true

JSON with the Fetch API

async function students() {
  try {
    // GET — fetch data
    const response = await fetch("/api/student", {
      method: "GET",
      headers: {
        "Content-Type": "application/json"
      }
    });

    if (!response.ok) throw new Error(`HTTP ${response.status}`);

    const data = await response.json(); // automatic JSON.parse
    return data;
  } catch (error) {
    console.error("Failed to fetch data:", error);
    return [];
  }
}

async function addStudent(student) {
  try {
    const response = await fetch("/api/student", {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(student) // automatic JSON.stringify
    });

    if (!response.ok) throw new Error(`HTTP ${response.status}`);

    return await response.json();
  } catch (error) {
    console.error("Failed to add data:", error);
    return null;
  }
}

Code Explanation

Function Explanation
JSON.stringify(obj, replacer, space) Convert an object to a JSON string
JSON.parse(string, reviver) Convert a JSON string to an object
replacer An array of properties or a function to filter/transform while stringifying
reviver A function to transform values while parsing
try-catch Required to handle invalid JSON

What JSON CANNOT Handle

❌ Function    → lost during stringify
❌ undefined   → lost during stringify
❌ Symbol      → error during stringify
❌ Infinity    → becomes null
❌ NaN         → becomes null
❌ Date        → becomes an ISO string (not a Date object)
❌ RegExp      → becomes an empty object {}

Real-World Examples

A grade notes system using localStorage:

class CampusNotes {
  constructor() {
    this.key = "campus_data";
    this.data = this.muat();
  }

  muat() {
    try {
      const json = localStorage.getItem(this.key);
      return json ? JSON.parse(json) : { student: [], course: [] };
    } catch {
      return { student: [], course: [] };
    }
  }

  save() {
    try {
      localStorage.setItem(this.key, JSON.stringify(this.data, null, 2));
      return true;
    } catch (error) {
      console.error("Failed to save:", error);
      return false;
    }
  }

  addStudent(name, studentId, major) {
    const new = {
      id: Date.now(),
      name,
      studentId,
      major,
      grade: {},
      created: new Date().toISOString()
    };
    this.data.student.push(new);
    this.save();
    return new;
  }

  inputGrade(studentId, courseCode, grade) {
    const student = this.data.student.find(m => m.studentId === studentId);
    if (!student) return { success: false, message: "Student not found" };

    student.grade[courseCode] = grade;
    this.save();
    return { success: true, message: `Grade ${grade} added for ${student.name}` };
  }

  printTranscript(studentId) {
    const student = this.data.student.find(m => m.studentId === studentId);
    if (!student) return "Student not found";

    let transcript = `\n=== Transcript Grade ===\n`;
    transcript += `Name: ${student.name}\nStudentID: ${student.studentId}\nMajor: ${student.major}\n\n`;

    const entries = Object.entries(student.grade);
    if (entries.length === 0) {
      transcript += "None yet grade.\n";
    } else {
      let total = 0;
      for (const [mk, grade] of entries) {
        transcript += `${mk}: ${grade}\n`;
        total += grade;
      }
      const average = (total / entries.length).toFixed(2);
      transcript += `\nAverage: ${average}\n`;
    }

    return transcript;
  }

  eksporJSON() {
    const json = JSON.stringify(this.data, null, 2);
    const blob = new Blob([json], { type: "application/json" });
    const url = URL.createObjectURL(blob);

    const a = document.createElement("a");
    a.href = url;
    a.download = `campus_backup_${new Date().toISOString().slice(0, 10)}.json`;
    a.click();
    URL.revokeObjectURL(url);
  }
}

// Usage
const catatan = new CampusNotes();

catatan.addStudent("Mike Johnson", "2024001", "Computer Science");
catatan.addStudent("Anna Reed", "2024002", "Information Systems");

catatan.inputGrade("2024001", "IF101_Algoritma", 85);
catatan.inputGrade("2024001", "IF102_Database", 90);
catatan.inputGrade("2024002", "SI101_Accounting", 88);

console.log(catatan.printTranscript("2024001"));
// === Transcript Grade ===
// Name: Mike Johnson
// StudentID: 2024001
// Major: Computer Science
//
// IF101_Algoritma: 85
// IF102_Database: 90
//
// Average: 87.50

// Export to a JSON file
catatan.eksporJSON();

Conclusion

  • JSON.stringify() converts an object to a JSON string — use null, 2 for pretty printing.
  • JSON.parse() converts a JSON string to an object — always wrap it in try-catch.
  • A replacer filters properties while stringifying, and a reviver transforms values while parsing.
  • JSON doesn't support function, undefined, Symbol, Date (becomes a string), and Infinity.
  • localStorage only stores strings — always stringify before saving and parse when loading.