第一百二十七節,JavaScript,JSON數據類型轉換,數據轉換成字符串,字符串轉換成數據javascript
學習要點:html
1.JSON語法java
2.解析和序列化git
前兩章咱們探討了XML的結構化數據,但開發人員仍是以爲這種微型的數據結構仍是過於煩瑣、冗長。爲了解決這個問題,JSON的結構化數據出現了。JSON是JavaScript的一個嚴格的子集,利用JavaScript中的一些模式來表示結構化數據。redis
一.JSON語法express
JSON和XML類型,都是一種結構化的數據表示方式。因此,JSON並非JavaScript獨有的數據格式,其餘不少語言均可以對JSON進行解析和序列化。json
JSON的語法能夠表示三種類型的值:數組
1.簡單值:能夠在JSON中表示字符串、數值、布爾值和null。但JSON不支持JavaScript中的特殊值undefined。瀏覽器
2.對象:顧名思義。安全
3.數組:顧名思義。
簡單值JSON表示
100、"Lee" 這兩個量就是JSON的表示方法,一個是JSON數值,一個是JSON字符串。布爾值和null也是有效的形式。但實際運用中要結合對象或數組。
//json簡單值表示方式 10 //數字類型 "字符串" //字符串類型 true //布爾值類型 null //空
對象JSON表示
//對象 //JavaScript對象字面量表示法: var box = { name: 'Lee', age: 100 }; //而JSON中的對象表示法須要加上雙引號,而且不存在賦值運算和分號: '{"name":"Lee","age":100}' //使用雙引號,不然轉換會出錯
數組JSON表示
// 數組 // JavaScript數組字面量表示法: var box = [100, 'Lee', true]; // 而JSON中的數組表示法一樣沒有變量賦值和分號: '[100, "Lee", true]'
通常比較經常使用的一種複雜形式是數組結合對象的形式JSON表示:
//數組結合對象的形式 [ { "title" : "a", "num" : 1 }, { "title" : "b", "num" : 2 }, { "title" : "c", "num" : 3 } ]
PS:通常狀況下,咱們能夠把JSON結構數據保存到一個文本文件裏,而後經過XMLHttpRequest對象去加載它,獲得這串結構數據字符串(XMLHttpRequest對象將在Aajx章節中詳細探討)。因此,咱們能夠模擬這種過程。
模擬加載JSON文本文件的數據,而且賦值給變量。
var box = '[{"name" : "a","age" : 1},{"name" : "b","age" : 2}]';
PS;上面這短代碼模擬了var box = load('demo.json');賦值過程。由於經過load加載的文本文件,無論內容是什麼,都必須是字符串。因此兩邊要加上雙引號。
其實JSON就是比普通數組多了兩邊的雙引號,普通數組以下:
var box = [{name : 'a', age : 1},{name : 'b', age : 2}];
二.解析和序列化
若是是載入的JSON文件,咱們須要對其進行使用,那麼就必須對JSON字符串解析成原生的JavaScript值。固然,若是是原生的JavaScript對象或數組,也能夠轉換成JSON字符串。
對於講JSON字符串解析爲JavaScript原生值,早期採用的是eval()函數。但這種方法既不安全,可能會執行一些惡意代碼。
eval()函數,JSON字符串解析爲JavaScript原生值,參數是要解析的字符串
使用方式:
eval(要解析的字符串)
//模擬加載JSON字符串 var box = '[{"name" : "a","age" : 1},{"name" : "b","age" : 2}]'; alert(box); //JSON字符串 var json = eval(box); //使用eval()函數解析 alert(json); //獲得JavaScript原生值
JSON對象
ECMAScript5對解析JSON的行爲進行規範,定義了全局對象JSON。支持這個對象的瀏覽器有IE8+、Firefox3.5+、Safari4+、Chrome和Opera10.5+。不支持的瀏覽器也能夠經過一個開源庫json.js來模擬執行。JSON對象提供了兩個方法,一個是將原生JavaScript值轉換爲JSON字符串:stringify();另外一個是將JSON字符串轉換爲JavaScript原生值:parse()。
若是瀏覽器版本過低不支持JSON對象,經過一個開源庫json2.js來模擬執行,若是支持JSON對象就用JSON對象
json2.js開源庫
/* json2.js 2012-10-08 Public Domain. NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. See http://www.JSON.org/js.html This code should be minified before deployment. See http://javascript.crockford.com/jsmin.html USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO NOT CONTROL. This file creates a global JSON object containing two methods: stringify and parse. JSON.stringify(value, replacer, space) value any JavaScript value, usually an object or array. replacer an optional parameter that determines how object values are stringified for objects. It can be a function or an array of strings. space an optional parameter that specifies the indentation of nested structures. If it is omitted, the text will be packed without extra whitespace. If it is a number, it will specify the number of spaces to indent at each level. If it is a string (such as '\t' or ' '), it contains the characters used to indent at each level. This method produces a JSON text from a JavaScript value. When an object value is found, if the object contains a toJSON method, its toJSON method will be called and the result will be stringified. A toJSON method does not serialize: it returns the value represented by the name/value pair that should be serialized, or undefined if nothing should be serialized. The toJSON method will be passed the key associated with the value, and this will be bound to the value For example, this would serialize Dates as ISO strings. Date.prototype.toJSON = function (key) { function f(n) { // Format integers to have at least two digits. return n < 10 ? '0' + n : n; } return this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z'; }; You can provide an optional replacer method. It will be passed the key and value of each member, with this bound to the containing object. The value that is returned from your method will be serialized. If your method returns undefined, then the member will be excluded from the serialization. If the replacer parameter is an array of strings, then it will be used to select the members to be serialized. It filters the results such that only members with keys listed in the replacer array are stringified. Values that do not have JSON representations, such as undefined or functions, will not be serialized. Such values in objects will be dropped; in arrays they will be replaced with null. You can use a replacer function to replace those with JSON values. JSON.stringify(undefined) returns undefined. The optional space parameter produces a stringification of the value that is filled with line breaks and indentation to make it easier to read. If the space parameter is a non-empty string, then that string will be used for indentation. If the space parameter is a number, then the indentation will be that many spaces. Example: text = JSON.stringify(['e', {pluribus: 'unum'}]); // text is '["e",{"pluribus":"unum"}]' text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' text = JSON.stringify([new Date()], function (key, value) { return this[key] instanceof Date ? 'Date(' + this[key] + ')' : value; }); // text is '["Date(---current time---)"]' JSON.parse(text, reviver) This method parses a JSON text to produce an object or array. It can throw a SyntaxError exception. The optional reviver parameter is a function that can filter and transform the results. It receives each of the keys and values, and its return value is used instead of the original value. If it returns what it received, then the structure is not modified. If it returns undefined then the member is deleted. Example: // Parse the text. Values that look like ISO date strings will // be converted to Date objects. myData = JSON.parse(text, function (key, value) { var a; if (typeof value === 'string') { a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); if (a) { return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6])); } } return value; }); myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { var d; if (typeof value === 'string' && value.slice(0, 5) === 'Date(' && value.slice(-1) === ')') { d = new Date(value.slice(5, -1)); if (d) { return d; } } return value; }); This is a reference implementation. You are free to copy, modify, or redistribute. */ /*jslint evil: true, regexp: true */ /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length, parse, prototype, push, replace, slice, stringify, test, toJSON, toString, valueOf */ // Create a JSON object only if one does not already exist. We create the // methods in a closure to avoid creating global variables. if (typeof JSON !== 'object') { JSON = {}; } (function () { 'use strict'; function f(n) { // Format integers to have at least two digits. return n < 10 ? '0' + n : n; } if (typeof Date.prototype.toJSON !== 'function') { Date.prototype.toJSON = function (key) { return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z' : null; }; String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) { return this.valueOf(); }; } var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { // table of character substitutions '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\' }, rep; function quote(string) { // If the string contains no control characters, no quote characters, and no // backslash characters, then we can safely slap some quotes around it. // Otherwise we must also replace the offending characters with safe escape // sequences. escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { // Produce a string from holder[key]. var i, // The loop counter. k, // The member key. v, // The member value. length, mind = gap, partial, value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value. if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); } // If we were called with a replacer function, then call the replacer to // obtain a replacement value. if (typeof rep === 'function') { value = rep.call(holder, key, value); } // What happens next depends on the value's type. switch (typeof value) { case 'string': return quote(value); case 'number': // JSON numbers must be finite. Encode non-finite numbers as null. return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': // If the value is a boolean or null, convert it to a string. Note: // typeof null does not produce 'null'. The case is included here in // the remote chance that this gets fixed someday. return String(value); // If the type is 'object', we might be dealing with an object or an array or // null. case 'object': // Due to a specification blunder in ECMAScript, typeof null is 'object', // so watch out for that case. if (!value) { return 'null'; } // Make an array to hold the partial results of stringifying this object value. gap += indent; partial = []; // Is the value an array? if (Object.prototype.toString.apply(value) === '[object Array]') { // The value is an array. Stringify every element. Use null as a placeholder // for non-JSON values. length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; } // Join all of the elements together, separated with commas, and wrap them in // brackets. v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v; } // If the replacer is an array, use it to select the members to be stringified. if (rep && typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { if (typeof rep[i] === 'string') { k = rep[i]; v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { // Otherwise, iterate through all of the keys in the object. for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } // Join all of the member texts together, separated with commas, // and wrap them in braces. v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v; } } // If the JSON object does not yet have a stringify method, give it one. if (typeof JSON.stringify !== 'function') { JSON.stringify = function (value, replacer, space) { // The stringify method takes a value and an optional replacer, and an optional // space parameter, and returns a JSON text. The replacer can be a function // that can replace values, or an array of strings that will select the keys. // A default replacer method can be provided. Use of the space parameter can // produce text that is more easily readable. var i; gap = ''; indent = ''; // If the space parameter is a number, make an indent string containing that // many spaces. if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } // If the space parameter is a string, it will be used as the indent string. } else if (typeof space === 'string') { indent = space; } // If there is a replacer, it must be a function or an array. // Otherwise, throw an error. rep = replacer; if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { throw new Error('JSON.stringify'); } // Make a fake root object containing our value under the key of ''. // Return the result of stringifying the value. return str('', {'': value}); }; } // If the JSON object does not yet have a parse method, give it one. if (typeof JSON.parse !== 'function') { JSON.parse = function (text, reviver) { // The parse method takes a text and an optional reviver function, and returns // a JavaScript value if the text is a valid JSON text. var j; function walk(holder, key) { // The walk method is used to recursively walk the resulting structure so // that modifications can be made. var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } // Parsing happens in four stages. In the first stage, we replace certain // Unicode characters with escape sequences. JavaScript handles many characters // incorrectly, either silently deleting them, or treating them as line endings. text = String(text); cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } // In the second stage, we run the text against regular expressions that look // for non-JSON patterns. We are especially concerned with '()' and 'new' // because they can cause invocation, and '=' because it can cause mutation. // But just to be safe, we want to reject all unexpected forms. // We split the second stage into 4 regexp operations in order to work around // crippling inefficiencies in IE's and Safari's regexp engines. First we // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we // replace all simple value tokens with ']' characters. Third, we delete all // open brackets that follow a colon or comma or that begin the text. Finally, // we look to see that the remaining characters are only whitespace or ']' or // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. if (/^[\],:{}\s]*$/ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { // In the third stage we use the eval function to compile the text into a // JavaScript structure. The '{' operator is subject to a syntactic ambiguity // in JavaScript: it can begin a block or an object literal. We wrap the text // in parens to eliminate the ambiguity. j = eval('(' + text + ')'); // In the optional fourth stage, we recursively walk the new structure, passing // each name/value pair to a reviver function for possible transformation. return typeof reviver === 'function' ? walk({'': j}, '') : j; } // If the text is not JSON parseable, then a SyntaxError is thrown. throw new SyntaxError('JSON.parse'); }; } }());
不管是JSON對象,仍是開源庫json2.js來模擬執行,都有兩個方法
JSON對象提供了兩個方法,一個是將原生JavaScript值轉換爲JSON字符串:stringify();另外一個是將JSON字符串轉換爲JavaScript原生值:parse()。
parse()方法,將JSON字符串轉換爲JavaScript原生數據,參數是JSON字符串,第二個可選參數能夠是函數
使用方式
JSON對象.parse(JSON字符串)
//注意:引入了開源庫json2,若是瀏覽器版本過低不支持JSON對象,經過一個開源庫json2.js來模擬執行,若是支持JSON對象就用JSON對象 var box = '[{"name" : "a","age" : 1},{"name" : "b","age" : 2}]'; //JSON字符串,特別注意,鍵要用雙引號 alert(box); var json = JSON.parse(box); //parse()方法,將JSON字符串轉換爲JavaScript原生數據,參數是JSON字符串 alert(json); //打印轉換後的JavaScript原生數據
解析JSON字符串方法parse()也能夠接受第二個參數,這樣能夠在還原出JavaScript值的時候替換成本身想要的值。
//注意:引入了開源庫json2,若是瀏覽器版本過低不支持JSON對象,經過一個開源庫json2.js來模擬執行,若是支持JSON對象就用JSON對象 var box = '[{"name" : "a","age" : 1},{"name" : "b","age" : 2}]'; //json字符串 var json = JSON.parse(box, function (key, value) { //第二個參數爲匿名函數,接受對象的鍵和值 if (key == 'name') { //判斷對象的鍵等於name return 'Mr. ' + value; //改變值 } else { return value; //返回值 } }); alert(json[0].name); //打印第一個對象的name值
stringify()方法,將JavaScript原生數據轉換爲JSON字符串,參數是JavaScript原生數據,[可選參數,第一個參數能夠是一個數組,也能夠是一個函數,用於過濾結果。第二個參數則表示是否在JSON字符串中保留縮進。]
使用方式
JSON對象.stringify(JavaScript原生數據)
//注意:引入了開源庫json2,若是瀏覽器版本過低不支持JSON對象,經過一個開源庫json2.js來模擬執行,若是支持JSON對象就用JSON對象 var box = [{name : 'a', age : 1},{name : 'b', age : 2}]; //JavaScript原生數據 alert(box); var json = JSON.stringify(box); //轉換成JSON字符串 alert(json); //自動雙引號
在序列化JSON的過程當中,stringify()方法還提供了兩個可選參數。第一個參數能夠是一個數組,也能夠是一個函數,用於過濾結果。第二個參數則表示是否在JSON字符串中保留縮進。
//注意:引入了開源庫json2,若是瀏覽器版本過低不支持JSON對象,經過一個開源庫json2.js來模擬執行,若是支持JSON對象就用JSON對象 var box = [{name : 'a', age : 1, height : 177},{name : 'b', age : 2, height : 188}]; //JavaScript原生數據 //stringify()方法還提供了兩個可選參數。第一個參數能夠是一個數組,也能夠是一個函數,用於過濾結果。第二個參數則表示是否在JSON字符串中保留縮進。 var json = JSON.stringify(box, ['name', 'age'], 4); //只解析name和age,過濾掉height,保留縮進4 alert(json); //打印JSON字符串
若是不須要保留縮進,則不填便可;若是不須要過濾結果,但又要保留縮進,則將過濾結果的參數設置爲null。若是採用函數,能夠進行復雜的過濾。
//注意:引入了開源庫json2,若是瀏覽器版本過低不支持JSON對象,經過一個開源庫json2.js來模擬執行,若是支持JSON對象就用JSON對象 var box = [{name: 'a', age: 1, height: 177}, {name: 'b', age: 2, height: 188}]; //JavaScript原生數據 //stringify()方法還提供了兩個可選參數。第一個參數能夠是一個數組,也能夠是一個函數,用於過濾結果。第二個參數則表示是否在JSON字符串中保留縮進。 var json = JSON.stringify(box, function (key, value) { //設置一個匿名函數,分別接受對象的鍵和值 switch (key) { //多重判斷key鍵 case 'name' : //若是鍵是name return 'Mr. ' + value; //將name值改變成 case 'age' : //若是鍵是age return value + '歲'; default : return value; } }, 4); alert(json); //返回改變後的json字符串
PS:保留縮進除了是普通的數字,也能夠是字符。
還有一種方法能夠自定義過濾一些數據,使用toJSON()方法,能夠將某一組對象裏指定返回某個值。
//注意:引入了開源庫json2,若是瀏覽器版本過低不支持JSON對象,經過一個開源庫json2.js來模擬執行,若是支持JSON對象就用JSON對象 var box = [{ name: 'a', age: 1, height: 177, toJSON: function () { return this.name; //返回當前對象的name } }, { name: 'b', age: 2, height: 188, toJSON: function () { return this.name; //返回當前對象的name } }]; var json = JSON.stringify(box); //最後返回對象裏的name值字符串 alert(json);
PS:因而可知序列化也有執行順序,首先先執行toJSON()方法;若是應用了第二個過濾參數,則執行這個方法;而後執行序列化過程,好比將鍵值對組成合法的JSON字符串,好比加上雙引號。若是提供了縮進,再執行縮進操做。