What is a JSON
type JSONPrimitive = string | boolean | number | null;
type JSONObject = { [k:string]: JSONValue };
type JSONArray = JSONValue[];
type JSONValue = JSONArray | JSONObject | JSONPrimitive;
Static function of JSON
The JSON (JavaScript Object Notation) is a general format to represent values and objects. It is described in the RFC 4627 standard. Initially, it was made for JavaScript, but many other languages have libraries to handle it as well. So itβs easy to use JSON for data exchange when the client uses JavaScript and the server is written in Ruby, PHP, Java, whatever.
JavaScript provides methods:
JSON.stringify
to convert objects into JSON.JSON.parse
to convert JSON back into an object.
let student = {
name: 'Vince',
age: 30,
isAdmin: false,
courses: ['html', 'css', 'js'],
spouse: null
};
let json = JSON.stringify(student);
console.log(typeof json); // we've got a string!
console.log(json);
/* JSON-encoded object:
'{
"name" : "Vince",
"age":30,
"isAdmin":false,
"course":['html','css','js'],
"spouse":null
}'π‘
Different between JSON.stringify obj and arr
let meetup = {
title: "Conference",
room: {
number: 23,
participants: ["john", "ann"]
}
};
JSON.stringify(meetup);
'{"title":"Conference",
"room":
{"number":23,
"participants":["john","ann"]
}
}'
JSON.stringify(meetup.room.participants);
'["john","ann"]'
JSON.stringify
can be applied to primitives as well.
JSON supports the following data types:
Objects
{ ... }
Arrays
[ ... ]
Primitives:
strings,
numbers,
boolean values
true/false
,null
.
// a number in JSON is just a number
console.log( JSON.stringify(1) ) // '1'
// a string in JSON is still a string, but double-quoted
console.log( JSON.stringify('test') ) // 'test'
console.log( JSON.stringify(true) ); // 'true'
console.log( JSON.stringify([1, 2, 3]) ); // '[1,2,3]'
Special case for string
// single quote can contain double quote
// '"a":5' but ""a":5" is invalid string
JSON.stringify('Hello "WORLD"');
'"Hello \\"WORLD\\""'
JSON is meant to be used for data-exchange so some of the data types in JS can't fit in and will be skipped by JSON
Namely:
Function properties(methods).Symbolic keys and values[Symbol.iterator]()'Properties that storeundefined
.
- Only JSON-serializable values (i.e. boolean, number,
null
, array, object) will be present in the input value.
let user = {
sayHi() { // ignored
alert("Hello");
},
[Symbol("id")]: 123, // ignored
something: undefined // ignored
};
alert( JSON.stringify(user) ); // {} (empty object)
Nested object
let meetup = {
title: "Conference",
room: {
number: 23,
participants: ["john", "ann"]
}
};
JSON.stringify(meetup);
' {"title": "Conference",
"room":{
"number":23,
"participants":["john","ann"]
}
}'
// objects
"{" + '"' + "a" + '":' + 5 + "}";
'{"a":5}'
// arrays
"[" + "1" + "2" +"3" + "]"
'[123]'
Implement JSON.stringify
Something to keep in mind when implementing JSON.stringify
Doule quote is single quote in string
String + String will be string
JSON.stringify string
const value = 'He said, "Hello!"';
return '"' + value.replace(/"/g, '\\"') + '"';
// Results in: "He said, \"Hello!\""
const jsonStringify = (value) => {
if (value === null) {
return "null";
}
if (
typeof value === "boolean" ||
typeof value === "number"
) {
return String(value);
}
if(typeof value === "string") {
const encapsulated = value.replace(/"/g, '\\"');
return '"' + encapsulated + '"'
}
// Convert to string to do string tempolation
if (Array.isArray(value)) {
const elements = value.map((val) => jsonStringify(val));
return "[" + elements.join(",") + "]";
}
if (typeof value === "object") {
const keys = Object.keys(value);
const properties = keys
.map((key) => {
const val = jsonStringify(value(key));
if (val !== undefined) {
return '"' + key + '":' + val;
}
})
.filter((prop) => prop !== undefined);
return "{" + properties.join(",") + "}";
}
return undefined;
};
Transforming replacer
let room = {
number: 23
};
let meetup = {
title: "Conference",
participants: [{name: "John"}, {name: "Alice"}],
place: room // meetup references room
};
room.occupiedBy = meetup; // room references meetup
console.log( JSON.stringify(meetup, function replacer(key, value) {
return (key == 'occupiedBy') ? undefined : value;
// If we return a value of undefined -> against JSON rules
// It will be removed from JSON
}));
{"title":"Conference","participants":[{"name":"John"},
{"name":"Alice"}],"place":{"number":23}}
Formatting:space
The third argument of JSON.stringify(value,replacer,space) is the number of spaces to use for pretty formatting
let user = {
name: "John",
age: 25,
roles: {
isAdmin: false,
isEditor: true
}
};
alert(JSON.stringify(user, null, 2));
/* two-space indents:
'{
"name": "John",
"age": 25,
"roles": {
"isAdmin": false,
"isEditor": true
}
}'
*/
/* for JSON.stringify(user, null, 4) the result would be more indented:
'{
"name": "John",
"age": 25,
"roles": {
"isAdmin" : false,
"isEditor": true
}
}'
*/
Custom "to JSON"
An object may provide a custom toJSON methods
let room = {
number: 23
};
let meetup = {
title: "Conference",
date: new Date(Date.UTC(2017, 0, 1)), //Date.prototype.JSON converts to string
room
};
alert( JSON.stringify(meetup) );
/*
{
"title":"Conference",
"date":"2017-01-01T00:00:00.000Z", // (1)
"room": {"number":23} // (2)
}
*/
We can write our own custom JSON to convert the object to the type we want
JSON.parse
To decode a JSON string, we need another method named JSON.parse
let value = JSON.parse(str, [reviver]);
// stringified array
let numbers = "[0, 1, 2, 3]";
numbers = JSON.parse(numbers);
alert( numbers[1] ); // 1
let userData = '
{ "name": "John",
"age": 35,
"isAdmin": false,
"friends": [0,1,2,3] }';
let user = JSON.parse(userData);
alert( user.friends[1] ); // 1
let json = `{
name: "John", // mistake: property name without quotes
"surname": 'Smith', // mistake: single quotes in value (must be double)
'isAdmin': false // mistake: single quotes in key (must be double)
"birthday": new Date(2000, 2, 3), // mistake: no "new" is allowed, only bare values
"friends": [0,1,2,3] // here all fine
}`;
Using reviver as middleware
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
let meetup = JSON.parse(str);
alert( meetup.date.getDate() ); // Error!
meetup.date // '2017-11-30T12:00:00.000Z'
let schedule = `{
"meetups": [
{"title":"Conference","date":"2017-11-30T12:00:00.000Z"},
{"title":"Birthday","date":"2017-04-18T12:00:00.000Z"}
]
}`;
schedule = JSON.parse(schedule, function(key, value) {
if (key == 'date') return new Date(value);
return value;
});
alert( schedule.meetups[1].date.getDate() ); // works!
Summary
JSON is a data format that has its own independent standard and libraries for most programming languages.
JSON supports plain objects, arrays, strings, numbers, booleans, and
null
.JavaScript provides methods JSON.stringify to serialize into JSON and JSON.parse to read from JSON.
Both methods support transformer functions for smart reading and writing.
If an object has
toJSON
, then it is called byJSON.stringify
.
Exercises
let room = {
number: 23
};
let meetup = {
title: "Conference",
occupiedBy: [{name: "John"}, {name: "Alice"}],
place: room
};
// circular references
room.occupiedBy = meetup;
meetup.self = meetup;
console.log(JSON.stringify(meetup,(key,value)=>{
if(key == "occupiedBy" | key == "self") {
return undefined
}
else {
return value;
}
}));
// {"title":"Conference","place":{"number":23}}
let room = {
number: 23
};
let meetup = {
title: "Conference",
occupiedBy: [{name: "John"}, {name: "Alice"}],
place: room
};
// circular references
room.occupiedBy = meetup;
meetup.self = meetup;
console.log(JSON.stringify(meetup, (key,value)=>{
if(key != "" && value == meetup ) {
return undefined;
}
else {
return value;
}
}));
// {"title":"Conference","occupiedBy":[{"name":"John"},
// {"name":"Alice"}],"place":{"number":23}}