JSON (commonly pronounced Jason) stands for JavaScript Object Notation. It is a data format for representing the properties of a JavaScript object as a string.
In computing, there are often instances where you need to convert data from one format to another. For instance, if you consider a JavaScript object, you may want to convert it into a String so that:
Conversely, you may eventually want to convert this string back into an object so that you can use it in your JavaScript application.
The process of converting an object into a string is referred to as serialization, while the process of converting it back is referred to as de-serialization.
In order to convert an object into a string, you need a data-format that specifies how the object should be mapped to a character string—for instance, how do you denote the properties and values of an object, and how do you encode the various data types such as numbers and arrays?
Historically most data formats have been binary: This meant that it was not possible for a human to read the formatted data and gain an understanding of its underlying structure or meaning. Typically, data was converted to and from the binary format using a proprietary algorithm.
In recent years, there has been a move toward plain-text data formats. The most notable example is XML, which uses a similar structure and syntax to HTML in order to differentiate properties from their values.
There is nothing inherently wrong with using XML to serialize JavaScript objects, and many web applications do use XML. For instance, this is a possible representation of a contact in XML:
<?xml version="1.0" encoding="UTF-8"?>
<contact>
<contactName>William Jones</contactName>
<phoneNumber>555-2941</phoneNumber>
<emailAddress>[email protected]</emailAddress>
<company>
<code>123</code>
<name>ABC Incorporated</name>
</company>
<notes></notes>
<lastContacted>2014-09-25</lastContacted>
</contact>
There are three main drawbacks with XML:
JSON alleviates all of these issues. The main beauty of JSON is that it maps directly to JavaScript. If you were to write out the structure of a JavaScript object on paper using the same syntax JavaScript uses for declaring objects, it would probably look identical to JSON.
JSON is also natively supported in the latest versions of JavaScript; therefore you do not need any libraries to work with JSON.
Finally, JSON is incredibly simple. It is described in a few hundred words on the following website: http://http://www.json.org.
The JSON representation of a contact may look like this:
{
"contactName":"William Jones",
"phoneNumber":"555-2941",
"emailAddress":"[email protected]",
"company":{
"code":123,
"name":"ABC Incorporated"
},
"notes":null,
"lastContacted":"2014-06-30T05:50:46.659Z"
}
Notice how similar this looks to the literal notation for declaring a JavaScript object?
It is possible to convert a JavaScript object into a string using the utility function JSON.stringify
. In order to demonstrate this, start by creating a contact object using the object literal notation:
> c1 = {
contactName: "William Jones",
phoneNumber:"555-2941",
emailAddress:"[email protected]",
company:{
code:123,
name:"ABC Incorporated"
},
notes:null
lastContacted: new Date()
}
Next, execute the following to store this as a string in the variable contactString:
> contactString = JSON.stringify(c1)
"{"contactName":"William Jones","phoneNumber":"555-2941","emailAddress":"[email protected]","company":{"code":123,"name":"ABC Incorporated"},"notes":null,"lastContacted":"2014-06-30T06:06:56.306Z"}"
Notice that the properties and values are all retained, but property names are all automatically embedded in double quotes.
JSON allows all the JavaScript data types to be represented in the serialized version. This ensures that when the string is eventually converted back into an object, the various properties retain their original data types.
“William Jones”
.code
property has a value of 123
.true
and false
.null
is used to represent a null value, as you can see with the notes
property.company
property demonstrates. This nesting can go to as many levels as you require.You can convert the string back into an object using the JSON.parse
function. The example in Figure 15.1 shows this and demonstrates that you can access the properties of the de-serialized object:
Although the JSON format is great for serializing properties, it cannot be used for serializing methods: Any methods present on the object are simply ignored when JSON.stringify
is invoked.
Although JavaScript is great for working with most JavaScript data types, it does come with certain limitations. One of the most difficult data types to handle is the Date
object.
There are many different ways to serialize dates. For instance, you could use their time in milliseconds:
new Date().getTime()
1404088573560
The time in milliseconds is a number that represents the number of milliseconds that have passed since midnight on January 1, 1970. This is not an ideal way to represent a date; among other reasons, it does not contain time-zone information.
You could also use the toString
method on the Date
object:
new Date().toString()
"Mon Jun 30 2014 12:36:01 GMT+1200 (New Zealand Standard Time)"
This is better because it does contain time-zone information. However, it also contains unnecessary information: The day of the week is implied by the date.
Ultimately, it does not really matter what format you choose, as long as it stores all the information you require. The most important thing is that everyone agrees on the same format, thereby allowing any serialized objects to be de-serialized by your web application.
For this reason, the JavaScript Date
object now supports a method called toJSON
, as you can see in the following example:
new Date().toJSON();
"2014-06-30T00:37:09.348Z"
This produces a date in the UTC time zone (essentially the same as Greenwich Mean Time), regardless of the time zone of the computer itself. The timezone is denoted by the trailing Z on the date format. The entire date/time string is formatted according to an ISO standard, which is widely used in computing.
If you look at the JSON example earlier in this lesson, you will see that the date was converted into a string conforming to this standard.
You may have noticed a problem in our example, however. When JSON.parse
was used to transform the string back into an object, the lastContacted
property was left as a string, rather than converted back into a Date
object.
This is not the desired behavior: You always want the serialization process to be completely reversible by the de-serialization process. Fortunately, there is a way around this problem.
The JSON.parse
function supports an optional second parameter referred to as a “reviver.” This can be used to convert values as they are transformed back onto the object. This parameter expects to be passed a function, which in turn will be passed every property as it is parsed. Where appropriate, the reviver can decide to modify the value of the property before it is set on the object.
In order to parse dates with a reviver function, you need to perform two tasks:
Date
object. The Date
object has a constructor that supports the ISO format; therefore, this is a simple process.You saw regular expressions earlier in the book when you validated form fields. JavaScript supports a literal notation for defining regular expressions: Any unquoted character string that starts with a forward slash is assumed to be a regular expression.
The regular expression that follows is reasonably complex, so it is not important that you understand it, but you should understand the approach:
dateReviver = function(name, value) {
var regExp = /ˆ(d{4})-(d{2})-(d{2})T(d{2}):(d{2}):(d{2}(?:.d*)?)Z$/
if (value && typeof value === 'string' && value.match(regExp)) {
return new Date(value);
} else {
return value;
}
}
This code starts by defining a regular expression that describes the pattern of characters you expect to find in a date field.
Next, the if
statement checks that you have been passed a value and that the value has a data type of string
. Finally, the if
statement checks whether the value matches the regular expression: If it does, then the match
method will return a non-null value.
If the value is determined to be a serialized version of a date, it is simply passed to the constructor of Date
, and the resulting object is returned. If it is not a date, you simply return the value untouched.
You can now use this function to de-serialize the contact into a new variable:
contact2 = JSON.parse(contactString, dateReviver);
If you now examine the lastContacted
property, you can confirm it is a Date
:
> typeof contact2.lastContacted
"object"
> contact2.lastContacted.toString()
"Mon Jun 30 2014 18:06:56 GMT+1200 (NZST)"
Notice that even though the serialized version used the UTC time zone, the de-serialized version has been converted back into my local time zone.
Just as the JSON.parse
function supports a reviver, the JSON.stringify
function supports an optional replacer function. This is identical to the reviver, except it allows you to convert values as they are serialized.
In this Try It, we will experiment with the JSON data format. As you have already seen, JSON is an extremely simple data format so you will use it for a slightly different purpose: cloning objects. To clone an object is to make a copy of it: We will look at how this can be achieved with JSON.
In order to complete this lesson, you will need the Chrome web browser. You may, however, want to complete these exercises in a text editor and copy the results to the console.
o = {
studentName: 'William Jones',
school: 'Middletown High School',
grades: [
{subject: 'English',
grade: 'A'},
{subject: 'Algebra',
grade: 'B+'},
{subject: 'Geometry',
grade: 'C'},
]
}
JSON.stringify
on the object passed in, and store the result in a new variable.JSON.parse
, and store the result in a new variable.18.119.122.82