20.2 Parsing and Serialization [Advanced JavaScript Programming 3rd Edition]

Having a syntax similar to JavaScript is not the whole reason why JSON is popular. A more important reason is that JSON data structures can be parsed into useful JavaScript objects. The advantages of JSON being parsed into JavaScript objects are obvious, compared to the cumbersome parsing of XML data structures into DOM documents and the cumbersome extraction of data from them. Taking the JSON data structure containing a set of books in the previous section as an example, after parsing it into a JavaScript object, the title of the third book can be obtained with the following simple line of code:

books[2].title

Of course, this assumes that the object obtained after parsing the JSON data structure is stored in the variable books. Take another look at the following code that looks up data in the DOM structure:

doc.getElementsByTagName("book")[2].getAttribute("title")

Looking at these redundant method calls, it's not hard to see why JSON is so popular with JavaScript developers. Since then, JSON has become the de facto standard for exchanging data in Web service development.

20.2.1 JSON Objects

Early JSON parsers basically used JavaScript's eval() function. Since JSON is a subset of JavaScript syntax, the eval() function can parse, interpret, and return JavaScript objects and arrays. ECMAScript 5 standardizes the behavior of parsing JSON and defines the global object JSON. Browsers that support this object are IE 8+, Firefox 3.5+, Safari 4+, Chrome, and Opera 10.5+. For older browsers, a shim is available: https://github.com/douglascrockford/JSON-js. In older browsers, using eval() to evaluate JSON data structures is risky as some malicious code may be executed. Using this shim is the best option for browsers that don't natively support JSON parsing.

JSON objects have two methods: stringify() and parse(). In the simplest case, these two methods are used to serialize JavaScript objects to JSON strings and parse JSON strings to native JavaScript values, respectively. E.g:

var book = {
	title: "Professional JavaScript",
	authors: ["Nicholas C. Zakas"],
	edition: 3,
	year: 2011
};
var jsonText = JSON.stringify(book);

Running
this example uses JSON.stringify() to serialize a JavaScript object to a JSON string and saves it in the variable jsonText. By default, the JSON string output by JSON.stringify() does not contain any space characters or indentation, so the string saved in jsonText looks like this:

{
	"title": "Professional JavaScript",
	"authors": ["Nicholas C. Zakas"],
	"edition": 3,
	"year": 2011
}

When serializing JavaScript objects, all function and prototype members are intentionally ignored and not reflected in the result. Also, any properties with a value of undefined are skipped. What ends up in the result are instance properties whose values ​​are valid JSON data types.
Pass the JSON string directly to JSON.parse() to get the corresponding JavaScript value. For example, an object similar to book can be created using the following code:

var bookCopy = JSON.parse(jsonText);

Note that although book and bookCopy have the same properties, they are two separate objects with no relationship whatsoever.
This method throws an error if the string passed to JSON.parse() is not valid JSON.

20.2.2 Serialization Options

In fact, JSON.stringify() can receive two additional parameters in addition to the JavaScript object to serialize, which are used to specify that the JavaScript object should be serialized differently. The first parameter is a filter, which can be an array or a function; the second parameter is an option indicating whether to preserve indentation in the JSON string. Using these two parameters, alone or in combination, provides more comprehensive and in-depth control over JSON serialization.

1. Filter the results

If the filter parameter is an array, then only the properties listed in the array will be included in the result of JSON.stringify(). Take a look at the example below.

var book = {
	"title": "Professional JavaScript",
	"authors": ["Nicholas C. Zakas"],
	edition: 3,
	year: 2011
};
var jsonText = JSON.stringify(book, ["title", "edition"]);

Run
JSON.stringify() The second parameter is an array containing two strings: "title" and "edition". These two properties correspond to the properties in the object to be serialized, so only these two properties will be included in the returned result string:

{"title":"Professional JavaScript","edition":3}

If the second argument is a function, the behavior is slightly different. The passed-in function takes two parameters, the property (key) name and the property value. According to the property (key) name, you can know how to handle the properties in the object to be serialized. The property name can only be a string, and when the value is not the value of a key-value pair structure, the key name can be an empty string.
To change the result of serializing an object, the value returned by the function is the value of the corresponding key. Note, however, that if the function returns undefined, the corresponding property will be ignored. Let's look at an example.

var book = {
	"title": "Professional JavaScript",
	"authors": ["Nicholas C. Zakas"],
	edition: 3,
	year: 2011
};
var jsonText = JSON.stringify(book,
function(key, value) {
	switch (key) {
	case "authors":
		return value.join(",")
	case "year":
		return 5000;
	case "edition":
		return undefined;
	default:
		return value;
	}
});

Run it
here, the function filter determines the result based on the passed key. If the key is "authors", concatenate the arrays into a string; if the key is "year", set its value to 5000; if the key is "edition", remove the property by returning undefined.
Finally, be sure to provide the default item, which returns the passed in value so that other values ​​can appear in the result normally. In fact, the first time this function filter is called, the key is an empty string and the value is the book object. The serialized JSON string looks like this:

{"title":"Professional JavaScript","authors":"Nicholas C. Zakas","year":5000}

Every object in the object to be serialized goes through a filter, so after every object in the array with these properties is filtered, every object will only contain "title", "authors", and "year" Attributes.

Firefox 3.5 and 3.6 have a bug in the JSON.stringify() implementation that occurs when a function is passed as the second parameter of the method, i.e. the function can only be used as a filter: returning undefined means skipping A property, and returning any other value will include the corresponding property in the result. Firefox 4 fixes this bug.

2. String indentation

The third parameter of the JSON.stringify() method is used to control indentation and whitespace in the result. If this parameter is a number, it represents the number of spaces to indent at each level. For example, to indent 4 spaces at each level, you can write code like this:

var book = {
    "title": "Professional JavaScript",
    "authors": ["Nicholas C. Zakas"],
    edition: 3,
    year: 2011
};
var jsonText = JSON.stringify(book, null, 4);

run it

The string saved in jsonText looks like this:

{
    "title": "Professional JavaScript",
    "authors": ["Nicholas C. Zakas"],
    "edition": 3,
    "year": 2011
}

I don't know if readers noticed or not, JSON.stringify() also inserts newlines in the resulting string to improve readability. As long as a valid parameter value that controls indentation is passed in, the resulting string will contain newlines. (Only indentation without wrapping makes little sense.) The maximum number of indented spaces is 10, and all values ​​greater than 10 are automatically converted to 10.
If the indent parameter is a string instead of a number, that string will be used as the indent character in the JSON string (no spaces are used). In the case of strings, the indent character can be set to a tab, or any character like two dashes.

var jsonText = JSON.stringify(book, null, " - -");

This way, the string in jsonText will look like this:

{
--"title": "Professional JavaScript",
--"authors": [
----"Nicholas C. Zakas"
--],
--"edition": 3,
--"year": 2011
}

Indented strings can be up to 10 characters long. If the string is longer than 10, only the first 10 characters will appear in the result.

3. toJSON() method

Sometimes, JSON.stringify() still can't meet the needs of custom serialization of some objects. In these cases, the toJSON() method can be defined on the object to return its own JSON data format. The native Date object has a toJSON() method that automatically converts a JavaScript Date object to an ISO 8601 date string (exactly the same as calling toISOString() on a Date object).
A toJSON() method can be added to any object, for example:

var book = {
	"title": "Professional JavaScript",
	"authors": ["Nicholas C. Zakas"],
	edition: 3,
	year: 2011,
	toJSON: function() {
		return this.title;
	}
};
var jsonText = JSON.stringify(book);

Running it
The above code defines a toJSON() method on the book object that returns the title of the book. Similar to the Date object, this object will also be serialized as a simple string instead of an object. You can make the toJSON() method return any value and it will work fine. For example, you could make this method return undefined, which would cause its value to become null if the containing object was embedded in another object, and undefined if it was a top-level object.
toJSON() can be used as a complement to function filters, so it is important to understand the internal order of serialization. Assuming an object is passed to JSON.stringify(), the order of serializing the object is as follows.
(1) If the toJSON() method exists and a valid value can be obtained through it, this method is called. Otherwise, the object itself is returned.
(2) If the second argument is provided, this function filter is applied. The value passed into the function filter is the value returned in step (1).
(3) Serialize each value returned in step (2) accordingly.
(4) If the third parameter is provided, the corresponding formatting is performed.
Whether you're considering defining a toJSON() method, considering using a function filter, or needing to use both, understanding this order is critical.

20.2.3 Parse Options

The JSON.parse() method can also receive another parameter, which is a function that will be called on each key-value pair. To distinguish the replacement (filter) function (replacer) received by JSON.stringify(), this function is called the reviver function (reviver), but in fact the signature of the two functions is the same - they both accept two parameters, A key and a value, and both need to return a value.
If the restore function returns undefined, it means that the corresponding key is to be removed from the result; if it returns another value, the value is inserted into the result. The restore function is often used when converting date strings to Date objects. E.g:

var book = {
	"title": "Professional JavaScript",
	"authors": ["Nicholas C. Zakas"],
	edition: 3,
	year: 2011,
	releaseDate: new Date(2011, 11, 1)
};
var jsonText = JSON.stringify(book);
var bookCopy = JSON.parse(jsonText,
function(key, value) {
	if (key == "releaseDate") {
		return new Date(value);
	} else {
		return value;
	}
});
alert(bookCopy.releaseDate.getFullYear());

Running
the above code first adds a releaseDate property to the book object, which holds a Date object. This object is serialized into a valid JSON string, which is then parsed and restored to a Date object in bookCopy. When the restore function encounters the "releaseDate" key, it creates a new Date object based on the corresponding value. The result is that a Date object is stored in the bookCopy.releaseDate property. Because of this, the getFullYear() method can be called based on this object.

More chapter tutorials: http://www.shouce.ren/api/view/a/15218

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326676691&siteId=291194637
Recommended