When you want to send some request to the server, in most situation you will send some data. But in which format you should send the data? Most of the time, these data contains lot of information. The format you are sending should be recognized by the backend server and interpret as well. If you send Javascript Object, there are few languages which cannot recognize this format. So Javascript Object is not right format to send. You can send string, but converting object data to string and parse it in the backend to the right data type is not a very convenient thing. For example -
let user = { name: "John", age: 30, toString() { return `{name: "${this.name}", age: ${this.age}}`; } }; alert(user); // {name: "John", age: 30}
…But in the process of development, new properties are added, old properties are renamed and removed. Updating such toString every time can become a pain. We could try to loop over properties in it, but what if the object is complex and has nested objects in properties? We’d need to implement their conversion as well. And, if we’re sending the object over a network, then we also need to supply the code to “read” our object on the receiving side.
For small information like just a name, or number, string format is fine. But when there are lots of information, String is inappropriate. JSON solves this problem. It is a format which is recognized by most programming language and easy to work with.
The JSON
(JavaScript Object Notation) is a general format to represent values and objects. 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 on Ruby/PHP/Java/Whatever.
This method converts objects into JSON.
let student = { name: 'John', age: 30, isAdmin: false, courses: ['html', 'css', 'js'], wife: null }; let json = JSON.stringify(student); alert(typeof json); // we've got a string! alert(json); /* JSON-encoded object: { "name": "John", "age": 30, "isAdmin": false, "courses": ["html", "css", "js"], "wife": null } */
The method JSON.stringify(student)
takes the object and converts it into a string.
The resulting json string is a called JSON-encoded
or serialized
or stringified
or marshalled
object. We are ready to send it over the wire or put into a plain data store.
Please note that a JSON-encoded object has several important differences from the object literal:
'John'
becomes "John"
.age:30
becomes "age":30
.Using JSON.stringify() not only you can convert Object to string. But also you can convert other data type too like String, Array, Boolean, Numbers etc.
// a number in JSON is just a number alert( JSON.stringify(1) ) // 1 // a string in JSON is still a string, but double-quoted alert( JSON.stringify('test') ) // "test" alert( JSON.stringify(true) ); // true alert( JSON.stringify([1, 2, 3]) ); // [1,2,3]
The great thing is that nested objects are supported and converted automatically.
let meetup = { title: "Conference", room: { number: 23, participants: ["john", "ann"] } }; alert( JSON.stringify(meetup) ); /* The whole structure is stringified: { "title":"Conference", "room":{"number":23,"participants":["john","ann"]}, } */
There are few properties that doesn't get included during the conversion -
undefined
let user = { sayHi() { // ignored alert("Hello"); }, [Symbol("id")]: 123, // ignored something: undefined // ignored }; alert( JSON.stringify(user) ); // {} (empty object)
If your object references in a circular direction, then the method JSON.stringify()
fails to convert to JSON. Consider the following example -
let room = { number: 23 }; let meetup = { title: "Conference", participants: ["john", "ann"] }; meetup.place = room; // meetup references room room.occupiedBy = meetup; // room references meetup
The property place
of meetup
object has the reference to the object room
. Now occupiedBy
property of room
object refers to the object meetup
. It mean both object refers to both object. If you try to convert that object to JSON, you will get an error.
JSON.stringify(meetup); // Error: Converting circular structure to JSON
Like toString
for string conversion, an object may provide method toJSON for to-JSON conversion. JSON.stringify
automatically calls it if available.
let room = { number: 23 }; let meetup = { title: "Conference", date: new Date(Date.UTC(2017, 0, 1)), room }; alert( JSON.stringify(meetup) ); /* { "title":"Conference", "date":"2017-01-01T00:00:00.000Z", "room": {"number":23} } */
Here we can see that date became a string. That’s because all dates have a built-in toJSON
method which returns such kind of string.
Now let’s add a custom toJSON
for our object room:
let room = { number: 23, toJSON() { return this.number; } }; let meetup = { title: "Conference", room }; alert( JSON.stringify(room) ); // 23 alert( JSON.stringify(meetup) ); /* { "title":"Conference", "room": 23 } */
As we can see, toJSON
is used both for the direct call JSON.stringify(room)
and for the nested object JSON.stringify(meetup)
.
The method JSON.parse() converts a JSON string to JS object. It does the reverse of the JSON.stringify()
.
let value = JSON.parse(str[, reviver]);
For example -
// stringified array let numbers = "[0, 1, 2, 3]"; numbers = JSON.parse(numbers); alert( numbers[1] ); // 1 // Also works for Nested Object - let user = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }'; user = JSON.parse(user); alert( user.friends[1] ); // 1
The JSON.parse()
method takes an optional function(key,value) as a second argument that will be called for each (key, value) pair and can transform the value. This argument is called Reviver
.
Imagine, we got a stringified meetup
object from the server.
// title: (meetup title), date: (meetup date) let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';
…And now we need to deserialize it, to turn back into JavaScript object.
Let’s do it by calling JSON.parse
:
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; let meetup = JSON.parse(str); alert( meetup.date.getDate() ); // Error!
The value of meetup.date
is a string, not a Date
object. How could JSON.parse
know that it should transform that string into a Date?
Let’s pass to JSON.parse
the reviving function that returns all values “as is”, but date will become a Date
:
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; let meetup = JSON.parse(str, function(key, value) { if (key == 'date') return new Date(value); return value; }); alert( meetup.date.getDate() ); // now works!
By the way, that works for nested objects as well:
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!