第67節 JSON物件-Web前端開發之JavaScript-零點程式設計師-王唯

本內容是《Web前端開發之Javascript影片》的課件,請配合大師哥《Javascript》影片課程學習。

由於在Javascript中操作XML存在嚴重的跨瀏覽器問題,且從XML結構中提取資料也要涉及遍歷DOM文件,Douglas Crockford(道格拉斯·克羅克福德)發明了一種名為JSON(JavaScript Object Notation,JavaScript物件表示法)的資料格式,用以避免使用XML資料的麻煩;

JSON是Javascript語法中的一個子集,利用了Javascript中的一些模式來表示結構化資料,特別是物件和陣列字面量;使用JSON能夠建立與XML相同的資料結構,它是一種輕量級的資料格式,可以簡化表示複雜資料結構的工作量;如:

{ “name”: “wangwei”, “title”: “Engineer”, “sex”: true, “age”: 18}

JSON並不從屬於Javascript,而且並不是只有Javascript才使用JSON,因為它只是一種資料格式,所以很多開發語言都有針對JSON的解析器和序列化器

JSON語法:

簡單值:

使用與Javascript相似的語法,在JSON中可以使用字串、數值、布林值和null;但JSON不支援Javascript中的特殊值undefined;

JSON字串與Javascript字串最大的區別是,JSON字串中的屬性名和屬性值必須使用雙引號,但屬性值如果是Boolean或Number型別的可以不用加雙引號,如:

// var data = ‘{“name”:“wangwei”,“title”:“engineer”,“sex”:true,“age”:18}’;// 改成單引號,丟擲Uncaught SyntaxErrorvar data = “{‘name’:‘wangwei’}”;console。log(JSON。parse(data));

在Javascript中,不要求給物件的屬性加引號,但在JSON字串中未加引號的屬性被視為一個語法錯誤;

在JSON中沒有變數宣告,在末尾也不需要分號

物件:JSON的值可以是簡單值,也可以是複雜型別,如:

{ “name”: “wangwei”, “sex”: true, “age”: 18, “company”: { “name”: “零點網路”, “url”: “https://www。zeronetwork。cn” }}

字串形式:

‘{“name”:“wangwei”,“sex”:true,“age”:18,“company”:{“name”:“零點網路”,“url”:“https://www。zeronetwork。cn”}}’

陣列:

JSON使用Javascript中的陣列字面量語法來表示陣列,陣列的值也可以是任意型別,即可以是簡單值、物件或陣列,如:

var values = [“wangwei”,true,18]; // javascript[“wangwei”,true,18] // JSON

字串表示:

‘[“wangwei”,true,18]’

如:

{ “name”: “WangWei”, “sex”: true, “age”: 18, “company”: { “name”: “零點網路”, “url”: “https://www。zeronetwork。cn” }, “friends”: [“JingJing”,“Juanzi”,“daguo”]}

字串表示:

var data = ‘{“name”:“wangwei”,“sex”:true,“age”:18,“company”:{“name”:“零點網路”,“url”:“https://www。zeronetwork。cn”},“friends”:[“JingJing”,“Juanzi”,“daguo”]}’;console。log(JSON。parse(data));

把陣列和物件結合起來,就可以構成更為複雜的資料集合,如:

[ { “name”: “WangWei”, “sex”: true, “age”: 18, “company”: { “name”: “零點網路”, “url”: “https://www。zeronetwork。cn” }, “friends”: [“JingJing”,“Juanzi”,“daguo”] }, { “name”: “JingJing”, “sex”: false, “age”: 20, “company”: { “name”: “零點培訓”, “url”: “https://edu。zeronetwork。cn” }, “friends”: [“wangwei”,“Juanzi”,“daguo”] }];

字串表示:

var data = ‘[{“name”:“WangWei”,“sex”:true,“age”:18,“company”:{“name”:“零點網路”,“url”:“https://www。zeronetwork。cn”},“friends”:[“JingJing”,“Juanzi”,“daguo”]},{“name”:“JingJing”,“sex”:false,“age”:20,“company”:{“name”:“零點培訓”,“url”:“https://edu。zeronetwork。cn”},“friends”:[“wangwei”,“Juanzi”,“daguo”]}]’;console。log(JSON。parse(data)); // Array

利用陣列和物件,可以創造出各種各樣的資料結構,這也是JSON最常用的資料結構;

JSON不支援變數、函式或物件例項;

序列化 (Serialization)及反序列化:

序列化是將物件的狀態資訊轉換為可以儲存或傳輸的形式的過程;在此期間,物件將其當前狀態寫入到臨時或永續性儲存區,之後,可以透過從儲存區中讀取或反序列化物件的狀態,重新建立該物件。

早期的JSON的實現原理:

JSON的設計意圖是在伺服器端構建格式化的資料,然後再將資料傳送給瀏覽器;由於JSON在JavaScript中相當於物件和陣列,因此JSON字串可以傳遞給eval()函式,讓其解析並返回一個物件或陣列的例項,如:

var data = ‘[{“name”: “wangwei”,“sex”: true,“age”: 18},{“name”: “JingJing”,“sex”: false,“age”: 20}]’;var jsonObj = eval(‘(’+data+‘)’);console。log(jsonObj);console。log(jsonObj[0]。name);

解析和序列化:

可以把JSON資料結構解析為Javascript物件;

由於JSON結構是被轉換為Javascript物件,所以訪問這種資料比XML更方便、解析速度更快,因此JSON成了替代XML的資料格式,成為了Web開發中交換資料的事實標準;

JSON物件有兩個方法:stringify()和parse(),分別用於把Javascript物件序列化為JSON字串和把JSON字串解析為原生Javascript值(物件);

JSON.stringify(value[, replacer [, space]])方法:

用於將一個JavaScript物件或值轉換為 JSON 字串;引數value為將要序列化成一個JSON字串的值或物件;引數replacer為一個可選的過濾器;可選引數space指定了如何縮排;返回值是一個JSON字串,如:

console。log(JSON。stringify({})); // ‘{}’console。log(JSON。stringify(true)); // ‘true’console。log(JSON。stringify(“wangwei”)); // ‘“wangwei”’console。log(JSON。stringify([1, “false”, false]));// ‘[1,“false”,false]’console。log(JSON。stringify({ x: 5, y: 6 })); // {“x”:5,“y”:6}console。log(JSON。stringify([new Number(3), new String(‘false’), new Boolean(false)]));// [3,“false”,false]var person = { name: “wangwei”, sex: true, age: 18, company: { name: “零點網路”, url: “https://www。zeronetwork。cn” }}var jsonText = JSON。stringify(person);console。log(person);console。log(jsonText);

布林值、數字、字串的包裝物件在序列化過程中會自動轉換成對應的原始值;

如果有前導零的話,會忽略該前導零;

非陣列物件的屬性不能保證以特定的順序出現在序列化後的字串中;

預設情況下,JSON。stringify()輸出的JSON字串不包含任何空格字元或縮排;

序列化物件時,所有函式及原型成員都會被忽略,不會體現在結果上;此外,值為undefined的任何屬性也都會被跳過,如:

var person = { name: “wangwei”, sex: true, age: 18, smoking: function(){}, marry: undefined}var jsonText = JSON。stringify(person);console。log(person);// {“name”:“wangwei”,“sex”:true,“age”:18}// smoking及marry被忽略了console。log(jsonText);

函式、undefined被單獨轉換時,會返回undefined,如:

console。log(JSON。stringify(function(){})); // undefinedconsole。log(JSON。stringify(undefined)); // undefined

值為NaN、Infinity和-Infinity序列化的結果是null;而日期物件序列化的結果是ISO格式的日期字串(與Date。toJSON()方法是一致的),但JSON。parse()會保留它們的字串的形態,不會將它們還原為原始日期物件;

var d = new Date(2021, 7, 13, 15, 6, 8);console。log(JSON。stringify(d));// “2021-08-13T07:06:08。000Z”console。log(d。toJSON());// 2021-08-13T07:06:08。000Zvar person = { “name”: “wangwei”, “sex”: true, “age”: 18, “isNaN”: NaN, “isInfinity”: Infinity, “birthday”: (new Date())};var jsonText = JSON。stringify(person);console。log(jsonText);var person = JSON。parse(jsonText);console。log(person);

JSON。stringify()只能序列化物件可列舉的自有屬性,如:

function Person(){ this。name = “wangwei”; this。sex = true;}Person。prototype = { constructor: Person, age: 18};var person = new Person();person。job = “engineer”;Object。defineProperty(person, “marry”, { value: true, // enumerable: true // [ɪˈnjuːməˈeɪbl] enumerable: false});console。log(person);for(var prop in person){ console。log(“person。” + prop + “=” + person[prop]);}console。log(Object。keys(person));console。log(JSON。stringify(person));

序列化選項:

json。stringify(value[, replacer [, space]])方法的value引數是需要序列化的Javascript物件,replacer與space用於指定以不同的方式序列化Javascript物件,其中replacer是一個替換(過濾)器,其可以是一個數組,也可以是一個函式;space引數表示是否在JSON字串中保留縮排;

單獨或組合使用這兩個引數,可以更全面深入的控制JSON的序列化結果;

replacer引數:

如果replacer是陣列,那麼JSON。stringify()的結果中將只包含陣列中列出的屬性,如:

var person = { name: “wangwei”, sex: true, age: 18, friends: [“JingJing”, “Juanzi”]}var jsonText = JSON。stringify(person, [“name”,“age”]);console。log(jsonText); // {“name”:“wangwei”,“age”:18}

如果過濾器陣列中指定的屬性在需要序列化的物件中不存在,會被忽略;

如果引數replacer是一個函式,則在序列化過程中,被序列化物件的每個屬性都會經過該函式的轉換和處理;該函式會在序列化的物件的作用域中執行,其引數是相應的屬性名key(鍵)和value屬性值,返回值就是該屬性的新值,如果函式返回了undefined,那麼相應的屬性會被忽略,如:

var jsonText = JSON。stringify(person, function(key, value){ switch(key){ case “name”: return “我的姓名:” + value; case “sex”: return value ? “男” : “女”; case “age”: return undefined; case “friends”: return “朋友:” + value。join(“,”); default: return value; }});// {“name”:“我的姓名:wangwei”,“sex”:“男”,“friends”:“朋友:JingJing,Juanzi”}console。log(jsonText);

在switch語句中,一定要有default語句,以便其他屬性值都能正常地出現在結果中;

並不是所有Javascript的值都可以使用JSON表示,如函式和undefined值無法透過JSON表示,包含它們的任何鍵預設都被移除,要改變這種預設的行為,就可以使用replacer函式,如:

var person = { name: “wangwei”, sex: true, age: 18, friends: undefined, smoking: function(){}}var jsonText = JSON。stringify(person, function(key, value){ if (value instanceof Function) { return “(function)”; }else if(value == undefined){ return “undefined”; }else{ return value; }});// {“name”:“wangwei”,“sex”:true,“age”:18,“friends”:“undefined”,“smoking”:“(function)”}console。log(jsonText);

replacer函式會遍歷所有屬性,但在第一次遍歷時,傳入的鍵是一個空字串,而值就是需要序列化的物件,如:

var jsonText = JSON。stringify(person, function(key, value){ console。log(key + “:” + value); return value;});// :[object Object]// name:wangwei// sex:true// age:18// friends:JingJing,Juanzi// 0:JingJing// 1:Juanzi

因此,可以透過判斷key是否是空字串,從而決定如何操作,如:

var jsonNumber = {1:1, 2:2, 3:3, 4:4, 5:5};var jsonText = JSON。stringify(jsonNumber, function(key, value){ console。log(key + “ = ” + value); if (key == “”) { return value; } return value * 2;});console。log(jsonText);

如果處理的某個屬性值是一個物件,則該函式會遍歷序列化該物件,其遍歷順序是由外向內;如:

var person = { name: “wangwei”, age: 18, friends: [“JingJing”,“Juanzi”], smoking: function(){}, company: { name: “零點網路”, contact:{ tel: “01088886666”, address: “北京市朝陽區” } }};var jsonText = JSON。stringify(person, function(key, value){ console。log(key + “:” + value); return value;});console。log(jsonText);

不能用replacer返回undefined的方式,從陣列中移除值,如若返回undefined或者一個函式,將會被null取代;如:

var arr = [“wangwei”, “jingjing”, “juanzi”];var jsonText = JSON。stringify(arr, function(key, value){ console。log(key + “ = ” + value); if (key == “”) { return value; } if (key == 1) { return undefined; } if (key == 2) { return function(){}; } return value;});console。log(jsonText);

space引數:

預設情況下,stringify()返回未經縮排的JSON字串;json。stringify()方法的的第三個引數space用於控制結果中的縮排和空白符;如果引數是一個數值,則表示的是每個級別縮排的空格數,如:

var person = { name: “wangwei”, sex: true, age: 18, friends: [“JingJing”,“Juanzi”]}var jsonText = JSON。stringify(person,null,4);// {// “name”: “wangwei”,// “sex”: true,// “age”: 18,// “friends”: [// “JingJing”,// “Juanzi”// ]// }console。log(jsonText);

其中結果字串中插入了換行符以及縮排;只要傳入有效的控制縮排的引數值,結果字串就會包含換行符;

最大縮排空格數為10,如果大於10會被自動轉換為10,值若小於1,則意味著沒有空格;

如果縮排引數是一個字串,則這個字串將在JSON字串中被用作縮排字元,如:

var jsonText = JSON。stringify(person,null,“——”);// {// ——“name”: “wangwei”,// ——“sex”: true,// ——“age”: 18,// ——“friends”: [// ——“JingJing”,// ——“Juanzi”// ——]// }console。log(jsonText);

在使用字串的情況下,也可以將縮排字元設定為製表符,或者其它任意字元;同樣的,縮排字串不能超過10個字元長,如果超過10個,只取前10個;

toJSON()方法:

JSON。stringify()在某些時候還不能滿足對某些物件進行自定義序列化的需求,在這種情況下,可以給物件定義toJSON()方法,返回其自身的JSON資料格式;

例如:原生Date物件有一個toJSON()方法,能夠將Date物件自動轉換成ISO8601日期字串(與在Date物件上呼叫toISOString()的結果完全一樣)如:

var d = new Date();console。log(d。toJSON());console。log(d。toISOString());console。log(JSON。stringify(d));

可以為任何物件新增toJSON()方法,如:

var person = { name: “wangwei”, sex: true, age: 18, friends: [“JingJing”,“Juanzi”], toJSON: function(){ return this。name; }}var jsonText = JSON。stringify(person);console。log(jsonText); // “wangwei”

可以讓toJSON()方法返回任何值,例如可以讓這個方法返回undefined,此時如果包含它的物件嵌入在另一個物件中,會導致它的值變成null,而如果它是頂級物件,結果就是undefined;

toJSON()方法可以作為replacer函式的補充,序列化該物件的順序如下:

1。如果存在toJSON(),而且能透過它取得有效的值,則呼叫該方法,否則,返回物件本身;

2。如果提供了replacer引數,則應用這個函式,傳入函式的值是第1步返回的值;

3。對第2步返回的每個值進行相應的序列化;

4。如果提供了space引數,則執行相應的格式化;

replacer函式中的this:

指向的就是當前級所對應的物件,如:

var jsonText = JSON。stringify(person,function(key,value){ console。log(key + “:” + value); console。log(this); return value;},4);

JSON.parse(text[, reviver])方法:

用來解析JSON字串,返回一個由字串描述構造出的JavaScript值或物件;引數text為要被解析成 JavaScript 值或物件的字串;可選引數reviver是一個轉換器函式,用以在返回之前對所得到的值執行變換(操作),如:

console。log(JSON。parse(‘{}’)); // {}console。log(JSON。parse(‘true’)); // trueconsole。log(JSON。parse(‘“wangwei”’)); // “wangwei”console。log(JSON。parse(‘[1, 5, “false”]’)); // [1, 5, “false”]console。log(JSON。parse(‘null’)); // null

如果傳給JSON。parse()的字串不是有效的JSON字串,該方法會丟擲異常;另外,JSON字串也不允許用逗號作為結尾;如:

JSON。parse(“[1, 2, 3, 4, ]”);JSON。parse(‘{“name”:“wangwei”, }’);

解析選項:

parse()方法的reviver是一個可選的轉換器函式,該函式將在每個鍵值對上呼叫,並以鍵key和值value作為引數,並且必須返回一個值,返回值將成為結果物件中與指定鍵關聯的值,如:

var jsonText = ‘{“name”:“wangwei”,“sex”:true,“age”:18,“friends”:[“JingJing”,“Juanzi”]}’;var p = JSON。parse(jsonText, function(key, value){ switch(key){ case “age”: return value + 1; case “sex”: return undefined; default: return value; }});console。log(p);console。log(p。age);

如果針對某個鍵返回undefined,就可以從結果物件中移除該鍵;

在將日期字串轉換為Date物件時,經常要用到reviver還原函式,如:

var person = { name: “wangwei”, sex: true, age: 18, birthday: new Date(2002,8,13)}var jsonText = JSON。stringify(person);console。log(jsonText);var newPerson = JSON。parse(jsonText, function(key, value){ if (key == “birthday”) { return new Date(value); }else{ return value; }});console。log(newPerson);console。log(newPerson。birthday);console。log(newPerson。birthday。getFullYear()); // 2002

如果沒有指定reviver函式,會直接解析出JavaScript值或物件,如果指定了reviver函式,則在解析前會經過一次轉換後,才將返回最終值;

在解析時,解析值本身以及它所包含的所有屬性,會按照一定的順序,即從最裡層的屬性開始,一級級往外,最終到達頂層,也就是解析值本身,按照這個順序分別去呼叫reviver函式;

var obj = JSON。parse(‘{“1”: 1, “2”: 2,“3”: {“4”: 4, “5”: {“6”: 6}}}’, function (k, v) { console。log(k); // 輸出當前的屬性名,從而得知遍歷順序是從內向外的, // 最後一個屬性名會是個空字串,也就是最頂層 return v; // 返回原始屬性值,相當於沒有傳遞reviver引數。}); // 1 2 4 6 5 3 “”console。log(obj);

當遍歷到最頂層的值(解析值)時,傳入reviver函式的引數是一個空字串 “”和當前的解析值,如:

var obj = JSON。parse(‘{“p”: 5}’, function (k, v) { if(k === ‘’) return v; // 如果到了最頂層,則直接返回屬性值, return v * 2; // 否則將屬性值變為原來的2倍。}); console。log(obj); // {p:10}

reviver中的this:

在呼叫過程中,當前屬性所屬的物件會作為this值,當到達最頂層時,this值會是 {“”: 修改過的解析值};

原生Javascript物件與JSON解析出來的物件,雖然具有相同的屬性,但兩者是完全不同的物件;

使用JSON。parse(JSON。stringify(obj)),可實現多維物件的深複製:

var person = { name: “wangwei”, sex: true, age: 18, isUndefined: undefined, isInfinity: Infinity, birthday: (new Date()), smoking: function(str){console。log(this。name + “:” + str)}, friends: [“jingjing”,“juanzi”], company: { name: “零點網路”, url: “https://www。zeronetwork。cn” }};console。log(JSON。parse(JSON。stringify(person)));

undefined及函式會被忽略,但也可以使用序列化選項及解析選項自定義還原;

var jsonText = JSON。stringify(person, function(key, value){ var type = typeof value; if (value == Infinity || type == “undefined” || type == “function”) { value = “[[” + value + “]]”; } return value;});console。log(jsonText);var person = JSON。parse(jsonText, function(key, value){ // 還原日期 var reg = /\d{4}。+\d{1,2}。+\d{1,2}/; if (typeof value == “string” && reg。test(value)) { value = new Date(value); } return value;});for(item in person){ // 還原undefined和function var value = person[item]; var reg = /\[\[(。*)\]\]/; if (typeof value == “string” && reg。test(value)) { value = value。match(reg)[1]; person[item] = eval(“(” + value + “)”); }}console。log(person);person。smoking(“吸菸”);//封裝function cloneJSON(source) { var jsonText = JSON。stringify(person, function(key, value){ var type = typeof value; if (value == Infinity || type == “undefined” || type == “function”) { value = “[[” + value + “]]”; } return value; }); var obj = JSON。parse(jsonText, function(key, value){ var reg = /\d{4}。+\d{1,2}。+\d{1,2}/; if (typeof value == “string” && reg。test(value)) { value = new Date(value); } return value; });; for(item in obj){ var value = obj[item]; var reg = /\[\[(。*)\]\]/; if (typeof value == “string” && reg。test(value)) { value = value。match(reg)[1]; obj[item] = eval(“(” + value + “)”); } } return obj;}var p = cloneJSON(person);console。log(person);console。log(p);

相容方案:

老版本的瀏覽器不支援JSON,例如IE7及以下不支援,但可以模仿原生JSON物件,如:

if (!window。JSON) { window。JSON = { parse: function(sJSON){ return eval(‘(’ + sJSON + ‘)’); }, stringify: (function(){ var toString = Object。prototype。toString; var isArray = Array。isArray || function(a){ return toString。call(a) === ‘[object Array]’; }; var escMap = {‘“’: ‘\\”’, ‘\\’: ‘\\\\’, ‘\b’: ‘\\b’, ‘\f’:‘\\f’, ‘\n’: ‘\\n’, ‘\r’: ‘\\r’, ‘\t’: ‘\\t’}; var escFunc = function(m){ return escMap[m] || ‘\\u’ + (m。charCodeAt(0) + 0x10000)。toString(16)。substr(1); }; var escRE = /[\\“\u0000-\u001F\u2028\u2029]/g; return function stringify(value){ if (value == null) { return ‘null’; }else if(typeof value === ‘number’){ return isFinite(value) ? value。toString() : ‘null’; }else if(typeof value === ‘boolean’){ return value。toString(); }else if (typeof value === ‘object’) { if (typeof value。toJSON === ‘function’) { return stringify(value。toJSON()); }else if (isArray(value)) { var res = ‘[’; for(var i=0; i

JSON2。js:

對於較早的瀏覽器不支援JSON,還可以使用Douglas Crockford自己維護的一個針對Javascript的JSON序列化器和解析器:https://github。com/duglascrockford/JSON-js,雖然它在舊版本的瀏覽器中,還是使用eval()函式進行物件的JSON資料結構求值,但對於不支援原生JSON解析的瀏覽器這是最佳的選擇;

cycle。js:

該庫包含兩個函式,JSON。decycle和JSON。retrocycle;這使得在JSON中對迴圈結構可以序列化,並且解析它們;目前,ES5中的JSON物件是實現不了迴圈結構的物件的序列化,此時就可以使用這個庫來實現;如:

var cycled = { foo: {}, bar: {}};cycled。foo。bar = cycled。foo;cycled。bar。foo = cycled。bar;console。log(cycled); // 原始物件var o = JSON。decycle(cycled); // 解除物件的迴圈引用console。log(o);var jsonText = JSON。stringify(o); // 序列化console。log(jsonText);var o = JSON。parse(jsonText); // 解析為無物件引用console。log(o);var obj = JSON。retrocycle(o); // 轉換為物件引用console。log(obj);

在Ajax中使用JSON:

在Ajax中,可以請求JSON資料,進而解析為JSON物件,如:

example。json:{ ”name“: ”wangwei“, ”sex“: true, ”age“: 18, ”friends“: [”JingJing“, ”Juanzi“]}JavaScript:var xhr = new XMLHttpRequest();xhr。onload = function(event){ var data = event。target。response; var h2 = document。createElement(”h2“); h2。innerText = data。name; document。body。appendChild(h2); var p = document。createElement(”p“); p。innerText = ”性別:“ + (data。sex ? ”男“ : ”女“) + ”,年齡:“ + data。name; document。body。appendChild(p); if (data。friends && data。friends instanceof Array) { var span = document。createElement(”span“); span。innerText = data。friends。join(”,“); p。appendChild(span); }}xhr。open(”GET“,”example。json“,true);xhr。responseType = ”json“;xhr。send(null);

示例:使用localStorage儲存JSON序列化後的資料,如:

if (localStorage。getItem(‘screenObj’)){ var restoredScreen = JSON。parse(localStorage。getItem(‘screenObj’)); console。log(restoredScreen);}else{ var screenObj = { screens : [], state : true }; screenObj。screens。push({name:”screenB“, width:650, height:350}); screenObj。screens。push({name:”screenC“, width:750, height:120}); screenObj。screens。push({name:”screenA“, width:450, height:250}); screenObj。screens。push({name:”screenD“, width:1240,height:650}); localStorage。setItem(‘screenObj’, JSON。stringify(screenObj));}

示例:克隆物件、將物件序列化儲存到SessionStorage中並讀取;如:

var JSON_Serialize_FIX = { PREFIX: ”[[JSON_FUN_PREFIX_“, SUFFIX: ”_JSON_FUN_SUFFIX]]“};function getSessionJSONItem(key, type){ if(type) key = key + ”_“ + type; return JSON。parse(sessionStorage。getItem(key), function(key, value){ if (typeof value == ”string“ && value。indexOf(JSON_Serialize_FIX。PREFIX) == 0 && value。indexOf(JSON_Serialize_FIX。SUFFIX) > 0) { return eval(”(“ + value。replace(JSON_Serialize_FIX。PREFIX, ”“) 。replace(JSON_Serialize_FIX。SUFFIX, ”“) + ”)“); } return value; }) || {};}function setSessionJSONItem(key, obj, type){ if(type) key = key + ”_“ + type; sessionStorage。setItem(key, JSON。stringify(obj, function(key, value){ if (typeof value == ‘function’) { return JSON_Serialize_FIX。PREFIX + value。toString() + JSON_Serialize_FIX。SUFFIX; } return value; }));}function cloneJSON(obj){ var jsonText= JSON。stringify(obj, function(key, value){ if (typeof value === ‘function’) { return JSON_Serialize_FIX。PREFIX + value。toString() + JSON_Serialize_FIX。SUFFIX; } return value; }); return JSON。parse(jsonText, function(key, value){ if (typeof value === ‘string’ && value。indexOf(JSON_Serialize_FIX。PREFIX) == 0 && value。indexOf(JSON_Serialize_FIX。SUFFIX) > 0) { return eval(”(“ + value。replace(JSON_Serialize_FIX。PREFIX, ”“) 。replace(JSON_Serialize_FIX。SUFFIX, ”“) + ”)“); } return value; }) || {};}var person = { name:”wangwei“, sex:true, age:18, smoking:function(){console。log(”smoking“)}};setSessionJSONItem(”person“, person, ”data“);console。log(getSessionJSONItem(”person“, ”data“));console。log(cloneJSON(person));

JSON使用場景:

JSON應用的場景比較多,如:

1。前後端資料傳輸;

2。Ajax非同步訪問資料;

3。RPC遠端呼叫;

4。生成Token;

5。介面返回資料:

6。充當配置檔案;

JSON與Excel:

示例:將json資料轉為table資料再進行Excel匯出;

第三方外掛和庫:

外掛JsonExportExcel。js:

地址:https://github。com/cuikangjie/JsonExportExcel

XLSX庫:

各種電子表格格式的解析器和編寫器,可以匯出為各種資料格式的檔案,地址:https://sheetjs。com/ 或https://github。com/SheetJS/sheetjs;

XLSX包含了很多的模組,完整的版本是dist/xlsx。full。min。js;

引用:

示例:把表格的內容匯出到Excel檔案中,如:

編號姓名年齡出生日期
1王唯182001-12-12
2JingJing192000-12-12
3Juanzi202009-10-10
標題 課時 主講
HTML 10 王唯
CSS 20 大師哥
JavaScript 30 零點程式設計師

可以把JSON資料匯出為Excel檔案,如:

function exportExcel(){ var persons = [ {name: ”王唯“, sex: ”男“, age: 18, createtime: new Date()}, {name: ”靜靜“, sex: ”女“, age: 19, createtime: new Date()}, {name: ”娟子“, sex: ”女“, age: 20, createtime: new Date()}, ]; var sheet = XLSX。utils。json_to_sheet(persons); XLSX。utils。book_append_sheet(workbook, sheet, ‘人員’); return XLSX。writeFile(workbook, ‘ExportJson。xlsx’);}

可以基於Excel的工作表sheet生成一個物件陣列,如:

function exportExcel(){ var url = ”files/one。xls“; var xhr = new XMLHttpRequest(); xhr。open(”GET“, url, true); xhr。responseType = ”arraybuffer“; xhr。onload = function(event){ var data = new Uint8Array(xhr。response); var workbook = XLSX。read(data, {type: ”array“}); var sheet = workbook。Sheets[workbook。SheetNames[0]]; console。log(sheet); var json = XLSX。utils。sheet_to_json(sheet); console。log(json); var jsonText = JSON。stringify(json); console。log(jsonText); }; xhr。send(null);}

TableExport:

該外掛可以將HTML表格匯出到xlsx、xls、csv和txt檔案;地址:https://github。com/clarketm/TableExport;但是它需要依賴xlsx及FileSaver。js庫;

var table = document。getElementsByTagName(”table“)[0];var tableExport = new TableExport(table);console。log(tableExport);

可以傳入其他屬性以自定義表、按鈕和匯出資料的外觀,如:

var tableExport = TableExport(document。getElementsByTagName(”table“)[0], { headers: true, // (Boolean), 是否顯示錶頭,即, 預設為true footers: true, // (Boolean), 是否顯示錶注,即,預設為false formats: [”xlsx“, ”csv“, ”txt“],// (String[]), 匯出的檔案格式,預設為[‘xlsx’, ‘csv’, ‘txt’] filename: ”id“, // (id, String), 匯出的檔名稱,預設為id‘ bootstrap: false, // (Boolean), 按鈕是否使用bootstrap樣式,預設為true exportButtons: true, // (Boolean), 是否自動為每個指定格式生成內建的匯出按鈕,預設為true position: ”bottom“, // (top, bottom), 標題的位置, 預設為’bottom‘ ignoreRows: null, // (Number, Number[]), 要從匯出檔案中排除的行索引,預設為null ignoreCols: null, // (Number, Number[]), 要從匯出的檔案中排除的列索引,預設為null trimWhitespace: true, // (Boolean), 從單元格文字中刪除所有前導/尾隨換行符、空格和製表符,預設為false RTL: false, // (Boolean), 將工作表的方向設定為從右向左,預設為false sheetname: ”id“ // (id, String), 工作表名稱,預設為’id‘});

JSON檔案的註釋:

JSON檔案是不能有註釋的,根據JSON規範(http://www。json。org, RFC 4627, RFC 7159),不支援註釋;JSON規範之所以不允許加註釋,主要是防止過多的註釋,會影響檔案本身的資料;

但是有些場合,尤其是配置檔案,還是希望能夠有幫助說明資料項的含義;一方面有利於描述介面,另一方面能夠減少重複性的文件,這在開發過程中有一定的意義;

註釋的方法:

1、使用約定的key作為註釋欄位:

如以”//“、”_comment“、”#####“(”#“個數自定) 作為註釋的key;但不符合規範,可以幾乎所有的JavaScript環境都允許;

2、使用重名key作為註釋:

即每個key,使用兩次,第1次做註釋,第2次做實際屬性,解析之後,只保留最後一項;也不符合規範,但幾乎所有的JavaScript環境也都允許

3、使用欄位key加字首做註釋key:

常用的字首有”?”、”#“、”_“、”__“等;優點是沒有重名的欄位,完全符合JSON協議;

4、使用JSON5規範:

JSON5規範允許在JSON檔案中加入註釋:單行註釋,多行註釋均可;其用法與內建的JSON物件類似;地址:https://json5。org/;

5、直接用json-schema:

使用規範中的註釋欄位,地址:http://json-schema。org/優點是功能強大,缺點是json-schema與json資料本身需要分離;

6、使用去註釋的庫:

可以使用strip-json-comments庫,它支援去掉行註釋與塊註釋,然後再可以用標準的JSON。parse解析;地址:https://github。com/sindresorhus/strip-json-comment;

7、使用支援註釋的配置檔案管理模組:

如rc庫,地址:https://github。com/dominictarr/rc,或者config庫,地址: https://github。com/lorenwest/node-config;缺點是隻能用於配置相關的Json檔案;

JSON工具和編輯器:

1。JSON格式化和驗證器:

一個線上工具,可以對JSON進行格式化和美化,以便更易於閱讀和除錯;地址:https://jsonformatter。curiousconcept。com/

2。Altova XMLSpy JSON和 XML編輯器:

是一款JSON和XML編輯工具,提供了用於編輯、建模、轉換和除錯XML相關技術的各種工具;主要的工具包括圖形化模式設計器、程式碼生成工具、檔案轉換器、偵錯程式以及用於處理XSLT、XSD、XBRL和SOAP的分析器;其利用RaptorXML Server進行JSON驗證和處理;地址:https://www。altova。com/xmlspy-xml-editor/download;

3。Code Beautify JSON工具

Code Beautify JSON工具包括JSON檢視器、JSON編輯器、JSON驗證器以及JSON到HTML、JSON到XML和JSON到YAML等轉換器;

還提供了Excel到JSON轉換器和JSON 縮小器;Code Beautify還為XML、HTML、CSV、CSS、RSS、SQL、Base64及其他資料格式和檔案型別提供了線上指令碼編輯器、美化器、縮小器和轉換器;地址:https://codebeautify。org/;

4。Visual Studio Code等IDE:

vsCode內建了支援編輯JSON檔案的功能;這包括透過IntelliSense針對屬性和值進行驗證、快速導航、程式碼摺疊和建議;將滑鼠懸停在JSON編輯視窗的左上角,會顯示當前JSON的資料結構等;

第67節 JSON物件-Web前端開發之JavaScript-零點程式設計師-王唯