Deep Dive into JSON, Parsing & Serialization
Reviewed & published by Brayan K
JSON (JavaScript Object Notation) is a lightweight, text-based data format for storing and exchanging structured data, which you turn into JavaScript values with JSON.parse() and back into text with JSON.stringify().
Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience: Download Node.js to run JavaScript on your computer, use your browser's Developer Console (Press F12) to test code snippets, or create a .html file with <script> tags and open it in your browser.
Master JSON handling: serialization, parsing, type preservation, circular references, validation, and production patterns.
What You'll Learn
- JSON stringify & parse
- Custom replacers & revivers
- Handling circular references
- Class serialization with type markers
- Schema validation
- JSON versioning & migrations
📦 Real-World Analogy: Universal Shipping Label
📋 JSON Data Types Quick Reference:
| Type | JSON Example | Notes |
|---|---|---|
| String | "hello" | Must use double quotes |
| Number | 42, 3.14 | No NaN or Infinity |
| Boolean | true, false | Lowercase only |
| Null | null | undefined is dropped from objects, but becomes null inside arrays |
| Array | [1, 2, 3] | Ordered list |
| Object | Keys must be strings |
What JSON Actually Is (And What It Cannot Represent)
JSON (JavaScript Object Notation) is a text-based data format, not JavaScript itself. It has strict rules and can only represent: objects, arrays, strings, numbers, booleans, and null.
- undefined - gets removed entirely
- Functions - removed entirely
- Dates - converted to ISO strings
- NaN / Infinity - become null
- RegExp, Map, Set - become empty objects
- Circular references - throws error
// What JSON can represent
const validData = {
string: "Hello",
number: 42,
boolean: true,
null: null,
array: [1, 2, 3],
object: { nested: "value" }
};
console.log(JSON.stringify(validData, null, 2));
// What JSON CANNOT represent (these get lost or converted)
const problematicData = {
undefined: undefined, // ❌ Removed entirely
function: function() {}, // ❌ Removed entirely
date: new Date(), // ⚠️ Becomes ISO string
nan: NaN, // ⚠️ Becomes null
infinity: Infinity, // ⚠️ Becomes null
regex: /pattern/g, // ❌ Becomes empty object {}
map: new Map([["a", 1]]), // ❌ Becomes empty object {}
set: new Set([1, 2, 3]) // ❌ Becomes empty object {}
};
console.log("\nProblematic data after stringify:");
console.log(JSON.stringify(problematicData, null, 2));
// Notice: undefined, function, regex, map, set are GONE!JSON.stringify — Serialization
Serialization converts JavaScript values into JSON text. Understanding how different types are handled is crucial to avoiding data loss.
// Basic serialization
const user = { name: "Boopie", age: 25 };
const json = JSON.stringify(user);
console.log(json);
console.log(typeof json); // "string"
// Pretty-printing with indentation
console.log("\nPretty-printed:");
console.log(JSON.stringify(user, null, 2));
// Date conversion (becomes ISO string)
const withDate = { created: new Date() };
console.log("\nDate becomes string:");
console.log(JSON.stringify(withDate));
// NaN and Infinity become null
const special = { nan: NaN, inf: Infinity, negInf: -Infinity };
console.log("\nSpecial numbers become null:");
console.log(JSON.stringify(special));
// undefined is removed from objects
const withUndefined = { a: 1, b: undefined, c: 3 };
console.log("\nUndefined removed:");
console.log(JSON.stringify(withUndefined)); // {"a":1,"c":3}JSON.parse — Deserialization
Parsing converts JSON text back to JavaScript values. JSON syntax is extremely strict — errors that JavaScript allows will crash JSON.parse.
// Basic parsing
const jsonText = '{"name":"Boopie","score":100}';
const obj = JSON.parse(jsonText);
console.log(obj.name); // "Boopie"
console.log(obj.score); // 100
// STRICT syntax rules - these will FAIL:
try {
// Keys must be double-quoted
JSON.parse("{name: 'value'}");
} catch (e) {
console.log("Error 1:", e.message);
}
try {
// Strings must use double quotes, not single
JSON.parse('{"name": \'value\'}');
} catch (e) {
console.log("Error 2:", e.message);
}
try {
// No trailing commas allowed
JSON.parse('{"a": 1, "b": 2,}');
} catch (e) {
console.log("Error 3:", e.message);
}
// Safe parsing wrapper
function safeParse(str) {
try {
return JSON.parse(str);
} catch {
return null;
}
}
console.log("\nSafe parse invalid:", safeParse("not json"));
console.log("Safe parse valid:", safeParse('{"valid": true}'));Custom Serialization with Replacers
The replacer parameter in JSON.stringify lets you filter keys, transform values, mask sensitive data, and preserve type information.
// Replacer as array - filter specific keys only
const user = {
id: 1,
name: "Boopie",
password: "secret123",
email: "[email protected]"
};
// Only include safe fields
const safeJson = JSON.stringify(user, ["id", "name", "email"]);
console.log("Filtered:", safeJson);
// Replacer as function - transform values
const data = {
name: "Boopie",
password: "secret123",
createdAt: new Date(),
balance: 1234.567
};
const transformed = JSON.stringify(data, (key, value) => {
// Mask sensitive fields
if (key === "password") return "***HIDDEN***";
// Format dates with type marker for revival
if (value instanceof Date) {
return { __type: "Date", value: value.toISOString() };
}
// Round numbers
if (typeof value === "number" && key === "balance") {
return Math.round(value * 100) / 100;
}
return value;
}, 2);
console.log("\nTransformed:");
console.log(transformed);Custom Parsing with Revivers
The reviver parameter in JSON.parse lets you restore Dates, class instances, and other types that JSON destroys during serialization.
// Reviver function to restore types
const jsonWithDate = '{"name":"Boopie","created":{"__type":"Date","value":"2025-01-15T10:30:00.000Z"}}';
const restored = JSON.parse(jsonWithDate, (key, value) => {
// Restore Date objects
if (value && value.__type === "Date") {
return new Date(value.value);
}
return value;
});
console.log("Name:", restored.name);
console.log("Created type:", restored.created.constructor.name);
console.log("Is Date?", restored.created instanceof Date);
console.log("Year:", restored.created.getFullYear());
// Auto-detect ISO date strings
const autoDateJson = '{"event":"Meeting","time":"2025-06-15T14:00:00.000Z"}';
const autoRestored = JSON.parse(autoDateJson, (key, value) => {
// Detect ISO date strings
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
const date = new Date(value);
if (!isNaN(date.getTime())) return date;
}
return value;
});
console.log("\nAuto-restored time:", autoRestored.time);
console.log("Is Date?", autoRestored.time instanceof Date);Worked Example — The Whole Round Trip
You have now seen stringify, parse, replacers and revivers separately. Here they are in one program, on one object, so you can see exactly what a round trip costs you and how to get it back. Read the comments first, then press Run and compare with the expected output at the bottom of the code.
// -- WORKED EXAMPLE - a full JSON round trip, and what it costs you --
// The object you have in memory. Note the deliberate mix of types.
const order = {
id: 7,
customer: "Priya",
total: 129.5,
paid: true,
coupon: null,
placedAt: new Date("2025-03-04T09:15:00.000Z"), // a real Date object
tags: ["priority", "gift"],
internalNote: undefined, // will not survive
recalculate: function () { return this.total; }, // will not survive
seenBy: new Set(["web"]) // will not survive as a Set
};
// STEP 1 - stringify. The third argument (2) is the indent, for readability.
const json = JSON.stringify(order, null, 2);
console.log(json);
// What happened to each awkward value:
// placedAt -> an ISO string, because Date has a built-in toJSON()
// internalNote -> gone. undefined keys are dropped from objects entirely
// recalculate -> gone. Functions cannot be represented in JSON at all
// seenBy -> {} . A Set has no toJSON, so it serialises as an empty object
// STEP 2 - parse it back and inspect the damage.
const revived = JSON.parse(json);
console.log("id is still a:", typeof revived.id);
console.log("placedAt is now a:", typeof revived.placedAt);
console.log("is it a Date?", revived.placedAt instanceof Date);
console.log("internalNote survived?", "internalNote" in revived);
console.log("seenBy is now:", JSON.stringify(revived.seenBy));
// STEP 3 - repair the Date with a REVIVER. JSON.parse calls this for every
// key/value pair, and whatever you return replaces that value.
const isIsoDate = (v) => typeof v === "string" && /^\d{4}-\d{2}-\d{2}T/.test(v);
const properlyRevived = JSON.parse(json, (key, value) => {
if (isIsoDate(value)) return new Date(value); // string turns back into a Date
return value; // everything else passes through
});
console.log("after the reviver, is it a Date?", properlyRevived.placedAt instanceof Date);
console.log("year:", properlyRevived.placedAt.getUTCFullYear());
// STEP 4 - a REPLACER is the same idea in the other direction. Here it hides a
// field that must never reach a log file or an API.
const withSecret = { user: "Priya", password: "hunter2", role: "admin" };
console.log(JSON.stringify(withSecret, (key, value) =>
key === "password" ? "***" : value
));
// Expected output:
// {
// "id": 7,
// "customer": "Priya",
// "total": 129.5,
// "paid": true,
// "coupon": null,
// "placedAt": "2025-03-04T09:15:00.000Z",
// "tags": [
// "priority",
// "gift"
// ],
// "seenBy": {}
// }
// id is still a: number
// placedAt is now a: string
// is it a Date? false
// internalNote survived? false
// seenBy is now: {}
// after the reviver, is it a Date? true
// year: 2025
// {"user":"Priya","password":"***","role":"admin"}The seenBy: {} line is the one that catches people in production. A Set does not error, does not warn, and does not vanish — it quietly turns into an empty object, and the bug shows up much later as "why is my list empty?".
🎯 Your Turn — Save, Load and Restore Settings
Three blanks, and they are the three things you will do with JSON every single day: write it out, read it back without crashing, and turn a date string into a real date again.
// 🎯 YOUR TURN - stringify, parse safely, then revive
// Everything is written for you except the three blanks marked ___
const settings = {
theme: "dark",
fontSize: 14,
lastOpened: new Date("2025-11-02T08:00:00.000Z"),
temp: undefined // watch this one disappear
};
// 👉 1) Turn 'settings' into JSON text indented by 2 spaces.
// JSON.stringify takes (value, replacer, indent) - pass null for replacer.
const json = ___;
console.log(json);
// 👉 2) Finish safeParse so bad input returns null instead of crashing the page.
// Replace ___ with the statement that parses 'text' and hands it back.
function safeParse(text) {
try {
___;
} catch (err) {
console.log("bad JSON:", err.name);
return null;
}
}
console.log("valid ->", JSON.stringify(safeParse(json)));
console.log("invalid ->", safeParse("{oops}"));
// 👉 3) The reviver runs for every key/value pair. Return a real Date object
// for lastOpened, built from the ISO string in 'value'.
const restored = JSON.parse(json, (key, value) => {
if (key === "lastOpened") return ___;
return value;
});
console.log("is a Date?", restored.lastOpened instanceof Date);
console.log("month (0-11):", restored.lastOpened.getUTCMonth());
// ✅ Expected output:
// {
// "theme": "dark",
// "fontSize": 14,
// "lastOpened": "2025-11-02T08:00:00.000Z"
// }
// valid -> {"theme":"dark","fontSize":14,"lastOpened":"2025-11-02T08:00:00.000Z"}
// bad JSON: SyntaxError
// invalid -> null
// is a Date? true
// month (0-11): 10Two things worth noticing in the expected output. temp is missing from the JSON, because its value was undefined. And bad JSON: SyntaxError prints before invalid -> null, because JavaScript has to evaluate safeParse(...) before it can log the line containing it.
Handling Circular References
Circular references (objects referencing themselves) crash JSON.stringify. You need a custom serializer to handle them safely.
// Circular references break JSON.stringify
const obj = { name: "Parent" };
obj.self = obj; // Circular!
try {
JSON.stringify(obj);
} catch (e) {
console.log("Error:", e.message);
}
// Safe stringify that handles circular references
function safeStringify(obj, space = 2) {
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;
}, space);
}
// Test with circular structure
const circular = { name: "Node" };
circular.child = { parent: circular };
console.log("\nSafe circular stringify:");
console.log(safeStringify(circular));
// Complex nested circular
const a = { id: "A" };
const b = { id: "B", ref: a };
a.ref = b;
console.log("\nMutual circular refs:");
console.log(safeStringify(a));Serializing Class Instances
When you serialize class instances, all methods are lost. Here's how to preserve and restore class types through JSON.
// Classes lose their methods when serialized
class User {
constructor(name, role) {
this.name = name;
this.role = role;
}
greet() {
return `Hello, I'm ${this.name}`;
}
isAdmin() {
return this.role === "admin";
}
}
const user = new User("Boopie", "admin");
console.log("Before serialize:");
console.log("greet():", user.greet());
console.log("isAdmin():", user.isAdmin());
// After JSON round-trip, methods are GONE
const json = JSON.stringify(user);
const parsed = JSON.parse(json);
console.log("\nAfter JSON round-trip:");
console.log("Data:", parsed);
console.log("Has greet?", typeof parsed.greet); // undefined!
// Solution: Custom serialization with type markers
function serializeWithType(obj) {
return JSON.stringify(obj, (key, value) => {
if (value instanceof User) {
return { __class: "User", data: { name: value.name, role: value.role } };
}
return value;
});
}
function deserializeWithType(json) {
return JSON.parse(json, (key, value) => {
if (value && value.__class === "User") {
return new User(value.data.name, value.data.role);
}
return value;
});
}
const serialized = serializeWithType(user);
console.log("\nSerialized with type:", serialized);
const revived = deserializeWithType(serialized);
console.log("\nRevived user:");
console.log("greet():", revived.greet());
console.log("isAdmin():", revived.isAdmin());JSON Schema Validation
Never trust incoming JSON blindly. Always validate the structure, types, and required fields before using data in your application.
// Manual schema validation (without external libraries)
function validateUserSchema(data) {
const errors = [];
if (typeof data !== "object" || data === null) {
return { valid: false, errors: ["Must be an object"] };
}
// Required fields
if (typeof data.id !== "number") {
errors.push("id must be a number");
}
if (typeof data.name !== "string" || data.name.length === 0) {
errors.push("name must be a non-empty string");
}
if (typeof data.email !== "string" || !data.email.includes("@")) {
errors.push("email must be a valid email");
}
// Optional fields with type checking
if (data.age !== undefined && typeof data.age !== "number") {
errors.push("age must be a number if provided");
}
if (data.roles !== undefined && !Array.isArray(data.roles)) {
errors.push("roles must be an array if provided");
}
return {
valid: errors.length === 0,
errors
};
}
// Test cases
const validUser = { id: 1, name: "Boopie", email: "[email protected]", age: 25 };
const invalidUser = { id: "wrong", name: "", email: "invalid" };
console.log("Valid user:", validateUserSchema(validUser));
console.log("\nInvalid user:", validateUserSchema(invalidUser));
// Safe parse with validation
function parseAndValidate(json, validator) {
try {
const data = JSON.parse(json);
const result = validator(data);
if (!result.valid) {
return { success: false, errors: result.errors };
}
return { success: true, data };
} catch (e) {
return { success: false, errors: ["Invalid JSON: " + e.message] };
}
}
const result = parseAndValidate('{"id":1,"name":"Test","email":"[email protected]"}', validateUserSchema);
console.log("\nParse & validate result:", result);JSON Transform Pipeline
Professional applications use pipelines to process JSON: safe parse → validate → transform → normalize. This pattern keeps data handling consistent and safe.
// Professional JSON processing pipeline
class JSONPipeline {
constructor() {
this.transformers = [];
}
addTransformer(fn) {
this.transformers.push(fn);
return this; // chainable
}
process(json) {
// Step 1: Safe parse
let data;
try {
data = JSON.parse(json);
} catch (e) {
return { success: false, error: "Parse failed: " + e.message };
}
// Step 2: Run transformers
try {
for (const transform of this.transformers) {
data = transform(data);
}
} catch (e) {
return { success: false, error: "Transform failed: " + e.message };
}
return { success: true, data };
}
}
// Create pipeline with transformers
const userPipeline = new JSONPipeline()
// Normalize strings
.addTransformer(data => ({
...data,
name: data.name?.trim(),
email: data.email?.toLowerCase().trim()
}))
// Add defaults
.addTransformer(data => ({
...data,
role: data.role || "user",
active: data.active ?? true
}))
// Parse dates
.addTransformer(data => ({
...data,
createdAt: data.createdAt ? new Date(data.createdAt) : new Date()
}));
const rawJson = '{"name":" Boopie ","email":"[email protected]","createdAt":"2025-01-15T10:00:00Z"}';
const result = userPipeline.process(rawJson);
console.log("Pipeline result:");
console.log(JSON.stringify(result, null, 2));
console.log("\nCreatedAt is Date?", result.data.createdAt instanceof Date);JSON Versioning & Migrations
As your data schema evolves, you need a migration strategy to upgrade old JSON to new formats without breaking existing data.
// JSON versioning for backward compatibility
const migrations = {
// v1 -> v2: renamed 'username' to 'name'
1: (data) => ({
...data,
version: 2,
name: data.username,
username: undefined
}),
// v2 -> v3: nested profile object
2: (data) => ({
version: 3,
profile: {
name: data.name,
email: data.email
},
settings: data.settings || {}
})
};
function migrateToLatest(data) {
const LATEST_VERSION = 3;
let current = { ...data };
// Default version 1 for old data without version
if (!current.version) {
current.version = 1;
}
// Apply migrations sequentially
while (current.version < LATEST_VERSION) {
const migrate = migrations[current.version];
if (!migrate) {
throw new Error(`No migration for version ${current.version}`);
}
console.log(`Migrating v${current.version} -> v${current.version + 1}`);
current = migrate(current);
}
return current;
}
// Test with old v1 data
const oldData = { username: "boopie", email: "[email protected]" };
console.log("Original (v1):", oldData);
const migrated = migrateToLatest(oldData);
console.log("\nMigrated to v3:", JSON.stringify(migrated, null, 2));
// v2 data only needs one migration
const v2Data = { version: 2, name: "boopie", email: "[email protected]" };
console.log("\nV2 data:", v2Data);
console.log("Migrated:", JSON.stringify(migrateToLatest(v2Data), null, 2));Safe JSON Storage (localStorage)
Storing JSON in localStorage requires error handling, expiration support, and protection against corrupted data.
// Safe localStorage with JSON
const storage = {
set(key, value, ttl = null) {
const item = {
value,
timestamp: Date.now(),
expires: ttl ? Date.now() + ttl : null
};
try {
localStorage.setItem(key, JSON.stringify(item));
return true;
} catch (e) {
console.error("Storage error:", e.message);
return false;
}
},
get(key) {
try {
const raw = localStorage.getItem(key);
if (!raw) return null;
const item = JSON.parse(raw);
// Check expiration
if (item.expires && Date.now() > item.expires) {
localStorage.removeItem(key);
return null;
}
return item.value;
} catch {
// Corrupted JSON
localStorage.removeItem(key);
return null;
}
},
remove(key) {
localStorage.removeItem(key);
}
};
// Demo (simulated for this environment)
console.log("Storage utility demo:");
// Simulating localStorage behavior
const mockStorage = {};
const mockSet = (k, v) => { mockStorage[k] = JSON.stringify(v); };
const mockGet = (k) => mockStorage[k] ? JSON.parse(mockStorage[k]) : null;
mockSet("user", { value: { name: "Boopie" }, timestamp: Date.now() });
console.log("Stored user:", mockGet("user"));
mockSet("temp", { value: "data", expires: Date.now() + 60000 });
console.log("Stored with TTL:", mockGet("temp"));Deep Cloning with JSON
The JSON.parse(JSON.stringify(obj)) pattern creates deep clones, but has significant limitations. Know when to use it and when to use structuredClone.
// JSON cloning - simple but has limitations
const original = {
name: "Boopie",
scores: [100, 95, 88],
settings: { theme: "dark" }
};
// JSON clone method
const jsonClone = JSON.parse(JSON.stringify(original));
// Modify clone - original is safe
jsonClone.scores.push(75);
jsonClone.settings.theme = "light";
console.log("Original scores:", original.scores);
console.log("Clone scores:", jsonClone.scores);
console.log("Original theme:", original.settings.theme);
console.log("Clone theme:", jsonClone.settings.theme);
// BUT... JSON clone fails for:
const problematic = {
date: new Date(),
regex: /pattern/,
func: () => "hello",
undef: undefined,
map: new Map([["a", 1]])
};
console.log("\nOriginal types:");
console.log("date:", problematic.date.constructor.name);
console.log("regex:", problematic.regex.constructor.name);
const cloned = JSON.parse(JSON.stringify(problematic));
console.log("\nAfter JSON clone:");
console.log("date:", typeof cloned.date); // string, not Date!
console.log("regex:", JSON.stringify(cloned.regex)); // empty object
console.log("func:", cloned.func); // undefined (removed)
console.log("undef:", cloned.undef); // undefined (removed)
// Modern alternative: structuredClone
// const better = structuredClone(problematic);
console.log("\n💡 Use structuredClone() for better deep cloning!");🏆 Mini-Challenge: A Safe Loader for Untrusted JSON
No blanks now — a brief, an outline and five test cases. This is the single most useful JSON function you will ever write: one that takes input you do not control and always hands back a predictable shape instead of an exception.
The [1,2,3] case is the one most people fail. typeof [] === "object", so a plain type check lets an array straight through, and your code then reads data.name off an array and gets undefined. Use Array.isArray().
JSON Best Practices
✅ DO
- Always wrap parse in try/catch
- Validate JSON structure before use
- Use replacers to preserve type info
- Use revivers to restore types
- Handle circular references safely
- Version your JSON schemas
- Use UTF-8 encoding
- Create transform pipelines
❌ DON'T
- Use eval() to parse JSON
- Assume API data is valid
- Store Dates without restoration plan
- Ignore type loss (undefined, functions)
- Mutate parsed JSON directly
- Use JSON for binary data
- Skip schema validation
- Ignore circular reference errors
🎯 Mastery Summary
- JSON is a strict text format — not all JS types survive serialization
- JSON.stringify converts to text; JSON.parse converts back
- Use replacers to filter/transform during serialization
- Use revivers to restore types during parsing
- Handle circular references with WeakSet tracking
- Preserve class instances with type markers
- Always validate incoming JSON before using it
- Build transform pipelines for consistent processing
- Version your schemas and create migrations
- Use structuredClone instead of JSON for complex deep cloning
Practice quiz
Which method converts a JavaScript value into a JSON string?
- JSON.parse()
- JSON.encode()
- JSON.stringify()
- JSON.toString()
Answer: JSON.stringify(). JSON.stringify() serializes a value to JSON text; JSON.parse() does the reverse.
What does JSON.parse() return?
- A JavaScript value
- A JSON string
- Always an object
- A Promise
Answer: A JavaScript value. JSON.parse() deserializes JSON text back into a JavaScript value.
What happens to a property whose value is undefined during JSON.stringify()?
- It becomes null
- It becomes the string 'undefined'
- It throws an error
- It is removed entirely
Answer: It is removed entirely. undefined (and functions) are dropped entirely from objects during serialization.
What do NaN and Infinity become when serialized with JSON.stringify()?
- 0
- null
- Strings
- They throw
Answer: null. NaN and Infinity cannot be represented in JSON, so they become null.
What happens to a Date when passed to JSON.stringify()?
- It becomes an ISO string
- It is removed
- It stays a Date object
- It becomes a number
Answer: It becomes an ISO string. A Date is converted to an ISO 8601 string; round-tripping does not restore it to a Date automatically.
What does JSON.stringify(obj) return when obj contains a circular reference?
- null
- An empty object
- It throws a TypeError
- The string '[Circular]'
Answer: It throws a TypeError. Circular references crash JSON.stringify with a TypeError unless you use a custom replacer.
Which JSON.parse input is valid?
- {name: 'value'}
- {"name": "value"}
- {"a": 1, "b": 2,}
- {'name': 'value'}
Answer: {"name": "value"}. JSON requires double-quoted keys and strings, and forbids trailing commas.
What is the typeof JSON.stringify({ a: 1 })?
- object
- number
- json
- string
Answer: string. stringify always produces a string.
What does a replacer ARRAY argument to JSON.stringify do?
- Renames keys
- Includes only the listed keys in the output
- Sorts the keys
- Removes all values
Answer: Includes only the listed keys in the output. Passing an array of key names whitelists which properties appear in the output.
After const c = JSON.parse(JSON.stringify({ date: new Date() })), what is typeof c.date?
- object
- number
- string
- undefined
Answer: string. JSON cloning turns the Date into an ISO string, so the clone's date is a string — a key limitation versus structuredClone.
Continue this course
- Previous: Writing Maintainable & Scalable Code Architecture
- Next: Client-Side Security Essentials (XSS, CSRF, Sanitisation) — Prevent the most common web security vulnerabilities in JS apps
- Quick reference: JavaScript cheat sheet