- JSON methods, toJSON
- JSON.stringify
- Excluding and transforming: replacer
- Formatting: space
- Custom “toJSON”
- JSON.parse
- Using reviver
- Summary
- Tasks
- Turn the object into JSON and back
- JavaScript JSON
- What is JSON?
- JSON Example
- JSON Example
- The JSON Format Evaluates to JavaScript Objects
- JSON Syntax Rules
- JSON Data — A Name and a Value
- JSON Objects
- JSON Arrays
- Converting a JSON Text to a JavaScript Object
- Example
JSON methods, toJSON
Let’s say we have a complex object, and we’d like to convert it into a string, to send it over a network, or just to output it for logging purposes.
Naturally, such a string should include all important properties.
We could implement the conversion like this:
let user = < name: "John", age: 30, toString() < return `", age: $>`; > >; alert(user); //
…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.
Luckily, there’s no need to write the code to handle all this. The task has been solved already.
JSON.stringify
The JSON (JavaScript Object Notation) is a general format to represent values and objects. It is described as in 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 on Ruby/PHP/Java/Whatever.
JavaScript provides methods:
- JSON.stringify to convert objects into JSON.
- JSON.parse to convert JSON back into an object.
For instance, here we JSON.stringify a student:
let student = < name: 'John', age: 30, isAdmin: false, courses: ['html', 'css', 'js'], spouse: 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"], "spouse": null >*/
The method JSON.stringify(student) takes the object and converts it into a string.
The resulting json string is called a 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:
- Strings use double quotes. No single quotes or backticks in JSON. So ‘John’ becomes «John» .
- Object property names are double-quoted also. That’s obligatory. So age:30 becomes «age»:30 .
JSON.stringify can be applied to primitives as well.
JSON supports following data types:
- Objects
- Arrays [ . ]
- Primitives:
- strings,
- numbers,
- boolean values true/false ,
- null .
// 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]
JSON is data-only language-independent specification, so some JavaScript-specific object properties are skipped by JSON.stringify .
- Function properties (methods).
- Symbolic keys and values.
- Properties that store undefined .
let user = < sayHi() < // ignored alert("Hello"); >, [Symbol("id")]: 123, // ignored something: undefined // ignored >; alert( JSON.stringify(user) ); // <> (empty object)
Usually that’s fine. If that’s not what we want, then soon we’ll see how to customize the process.
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":, > */
The important limitation: there must be no circular references.
let room = < number: 23 >; let meetup = < title: "Conference", participants: ["john", "ann"] >; meetup.place = room; // meetup references room room.occupiedBy = meetup; // room references meetup JSON.stringify(meetup); // Error: Converting circular structure to JSON
Here, the conversion fails, because of circular reference: room.occupiedBy references meetup , and meetup.place references room :
Excluding and transforming: replacer
The full syntax of JSON.stringify is:
let json = JSON.stringify(value[, replacer, space])
value A value to encode. replacer Array of properties to encode or a mapping function function(key, value) . space Amount of space to use for formatting
Most of the time, JSON.stringify is used with the first argument only. But if we need to fine-tune the replacement process, like to filter out circular references, we can use the second argument of JSON.stringify .
If we pass an array of properties to it, only these properties will be encoded.
let room = < number: 23 >; let meetup = < title: "Conference", participants: [, ], place: room // meetup references room >; room.occupiedBy = meetup; // room references meetup alert( JSON.stringify(meetup, ['title', 'participants']) ); // <"title":"Conference","participants":[<>,<>]>
Here we are probably too strict. The property list is applied to the whole object structure. So the objects in participants are empty, because name is not in the list.
Let’s include in the list every property except room.occupiedBy that would cause the circular reference:
let room = < number: 23 >; let meetup = < title: "Conference", participants: [, ], place: room // meetup references room >; room.occupiedBy = meetup; // room references meetup alert( JSON.stringify(meetup, ['title', 'participants', 'place', 'name', 'number']) ); /* < "title":"Conference", "participants":[,], "place": > */
Now everything except occupiedBy is serialized. But the list of properties is quite long.
Fortunately, we can use a function instead of an array as the replacer .
The function will be called for every (key, value) pair and should return the “replaced” value, which will be used instead of the original one. Or undefined if the value is to be skipped.
In our case, we can return value “as is” for everything except occupiedBy . To ignore occupiedBy , the code below returns undefined :
let room = < number: 23 >; let meetup = < title: "Conference", participants: [, ], place: room // meetup references room >; room.occupiedBy = meetup; // room references meetup alert( JSON.stringify(meetup, function replacer(key, value) < alert(`$: $`); return (key == 'occupiedBy') ? undefined : value; >)); /* key:value pairs that come to replacer: : [object Object] title: Conference participants: [object Object],[object Object] 0: [object Object] name: John 1: [object Object] name: Alice place: [object Object] number: 23 occupiedBy: [object Object] */
Please note that replacer function gets every key/value pair including nested objects and array items. It is applied recursively. The value of this inside replacer is the object that contains the current property.
The first call is special. It is made using a special “wrapper object”: . In other words, the first (key, value) pair has an empty key, and the value is the target object as a whole. That’s why the first line is «:[object Object]» in the example above.
The idea is to provide as much power for replacer as possible: it has a chance to analyze and replace/skip even the whole object if necessary.
Formatting: space
The third argument of JSON.stringify(value, replacer, space) is the number of spaces to use for pretty formatting.
Previously, all stringified objects had no indents and extra spaces. That’s fine if we want to send an object over a network. The space argument is used exclusively for a nice output.
Here space = 2 tells JavaScript to show nested objects on multiple lines, with indentation of 2 spaces inside an object:
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 >> */
The third argument can also be a string. In this case, the string is used for indentation instead of a number of spaces.
The space parameter is used solely for logging and nice-output purposes.
Custom “toJSON”
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", // (1) "room": // (2) > */
Here we can see that date (1) 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 (2) :
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 when room is nested in another encoded object.
JSON.parse
To decode a JSON-string, we need another method named JSON.parse.
let value = JSON.parse(str, [reviver]);
str JSON-string to parse. reviver Optional function(key,value) that will be called for each (key, value) pair and can transform the value.
// 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
The JSON may be as complex as necessary, objects and arrays can include other objects and arrays. But they must obey the same JSON format.
Here are typical mistakes in hand-written JSON (sometimes we have to write it for debugging purposes):
Besides, JSON does not support comments. Adding a comment to JSON makes it invalid.
There’s another format named JSON5, which allows unquoted keys, comments etc. But this is a standalone library, not in the specification of the language.
The regular JSON is that strict not because its developers are lazy, but to allow easy, reliable and very fast implementations of the parsing algorithm.
Using reviver
Imagine, we got a stringified meetup object from the server.
// title: (meetup title), date: (meetup date) let str = '';
…And now we need to deserialize it, to turn back into JavaScript object.
Let’s do it by calling JSON.parse :
let str = ''; 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 as the second argument, that returns all values “as is”, but date will become a Date :
let str = ''; 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": [ , ] >`; 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/writing.
- If an object has toJSON , then it is called by JSON.stringify .
Tasks
Turn the object into JSON and back
Turn the user into JSON and then read it back into another variable.
JavaScript JSON
JSON is often used when data is sent from a server to a web page.
What is JSON?
- JSON stands for JavaScript Object Notation
- JSON is a lightweight data interchange format
- JSON is language independent *
- JSON is «self-describing» and easy to understand
* The JSON syntax is derived from JavaScript object notation syntax, but the JSON format is text only. Code for reading and generating JSON data can be written in any programming language.
JSON Example
This JSON syntax defines an employees object: an array of 3 employee records (objects):
JSON Example
The JSON Format Evaluates to JavaScript Objects
The JSON format is syntactically identical to the code for creating JavaScript objects.
Because of this similarity, a JavaScript program can easily convert JSON data into native JavaScript objects.
JSON Syntax Rules
- Data is in name/value pairs
- Data is separated by commas
- Curly braces hold objects
- Square brackets hold arrays
JSON Data — A Name and a Value
JSON data is written as name/value pairs, just like JavaScript object properties.
A name/value pair consists of a field name (in double quotes), followed by a colon, followed by a value:
JSON names require double quotes. JavaScript names do not.
JSON Objects
JSON objects are written inside curly braces.
Just like in JavaScript, objects can contain multiple name/value pairs:
JSON Arrays
JSON arrays are written inside square brackets.
Just like in JavaScript, an array can contain objects:
In the example above, the object «employees» is an array. It contains three objects.
Each object is a record of a person (with a first name and a last name).
Converting a JSON Text to a JavaScript Object
A common use of JSON is to read data from a web server, and display the data in a web page.
For simplicity, this can be demonstrated using a string as input.
First, create a JavaScript string containing JSON syntax:
Then, use the JavaScript built-in function JSON.parse() to convert the string into a JavaScript object:
Finally, use the new JavaScript object in your page:
Example
document.getElementById(«demo»).innerHTML =
obj.employees[1].firstName + » » + obj.employees[1].lastName;
You can read more about JSON in our JSON tutorial.