以前用到JSON的場景也不少,但是沒有仔細的研究過,這幾天趁著一個需求用到了,就整理了一下相關用法。 一、 JSON.stringify() 1. 語法 JSON.stringify(value[, replacer [, space]]) 2. 先說一下後面兩個可選參數 space:是指定縮進用的 ...
以前用到JSON的場景也不少,但是沒有仔細的研究過,這幾天趁著一個需求用到了,就整理了一下相關用法。
一、 JSON.stringify()
1. 語法 JSON.stringify(value[, replacer [, space]])
2. 先說一下後面兩個可選參數
space:是指定縮進用的空白字元串,用於美化輸出,可以是數字或字元串。
1 const data = { 2 a: 'bang', 3 b: null, 4 c: { 5 x: 'xxx', 6 y: 'yyy', 7 z: 90 8 }, 9 d: 9527 10 } 11 JSON.stringify(data, null, 4) 12 // { 13 // "a": "bang", 14 // "b": null, 15 // "c": { 16 // "x": "xxx", 17 // "y": "yyy", 18 // "z": 90 19 // }, 20 // "d": 9527 21 // } 22 JSON.stringify(data, null, '-') 23 // { 24 // -"a": "bang", 25 // -"b": null, 26 // -"c": { 27 // --"x": "xxx", 28 // --"y": "yyy", 29 // --"z": 90 30 // -}, 31 // -"d": 9527 32 // }
replacer:轉化規則,可以是一個函數或數組。
1 // 1. 數組 2 const data = { 3 a: 'haha', 4 b: 123, 5 c: { 6 d: 8080, 7 e: null 8 } 9 }; 10 JSON.stringify(data, ['b', 'd']) 11 // {"b":123} 12 JSON.stringify(data, ['a', 'c']) 13 // {"a":"haha","c":{}} 14 JSON.stringify(data, ['a', 'c', 'e']) 15 // {"a":"haha","c":{"e":null}}
1 // 2. 函數 2 const data = { 3 a: 'haha', 4 b: 123, 5 c: { 6 b: '123', 7 d: 8080, 8 e: null 9 } 10 }; 11 function rep (key, value) { 12 if (key === 'b' && typeof value === 'number') return ++value; 13 return value; 14 } 15 JSON.stringify(data, rep) 16 // {"a":"haha","b":124,"c":{"b":"123","d":8080,"e":null}}
3. value
將要序列化成 一個 JSON 字元串的值。這裡面有一些類型是不能夠轉化的,undefined/function/symbol
1). undefined
JSON.stringify遇到undefined時,是無法被返回的,但是null是可以的,所以我在這裡的處理是把undefined 轉化成null
這麼做的理由是因為 undefined == null //true , 這樣處理後的數據是不影響做模糊判斷的。
2). function
同樣是無法被返回的一種類型,我的處理是轉成string類型存儲,這麼做產生的一個問題是 JSON.parse時需要再轉成function
1 let data = { 2 name: undefined, 3 age: 18, 4 type: null, 5 fn: ()=>{ 6 return 999; 7 } 8 }; 9 let rep = (key, value) => { 10 if (value === undefined) { 11 return null; 12 } 13 if (typeof value === 'function') { 14 return Function.prototype.toString.call(value); 15 } 16 return value; 17 } 18 JSON.stringify(data, rep) 19 //{"name":null,"age":18,"type":null,"fn":"()=>{\n return 999;\n }"}
3). symbol
es6新增的一種數據類型,具體留到另一篇文章里說。這裡還是說JSON的問題。
1 // 當value是Symbol 時,能被第二個參數指定,若不指定則無法返回 2 // 當key是Symbol 時,會被忽略,第二個參數無法指定 3 let data={name: 'aaa', symbol: Symbol()}; 4 data[Symbol()] = 'bbb'; 5 JSON.stringify(data,(key,value)=>{ 6 console.log(key,value); 7 // name aaa 8 // symbol Symbol() 9 if (typeof value === 'symbol') return 'symbol'; //只有在這裡指定才能返回結果 10 return value; 11 }); 12 //{"name":"aaa","symbol":"symbol"}
如果value 為Symbol,可以通過第二個參數來轉換;但是key為Symbol的話,遍歷的時候是無法遍歷到的,就無法返回,類似於不可枚舉類型:
1 let data = Object.create(null, { 2 name: { 3 value: 'aaa', 4 enumerable: true 5 }, 6 age: { 7 value: 18, 8 enumerable: false 9 } 10 }); 11 let a = JSON.stringify(data, (key, value) => { 12 console.log(key, value); 13 //name aaa 14 return value; 15 }) 16 console.log(a); 17 //{"name":"aaa"}
二、JSON.parse()
1. 語法: JSON.parse(text[, reviver])
2. 參數:reviver 轉換器, 如果傳入該參數(函數),可以用來修改解析生成的原始值,調用時機在parse函數返回之前。
1 let data = { 2 name: undefined, 3 age: 18, 4 type: null, 5 fn: () => { 6 return 999; 7 } 8 }; 9 let rep = (key, value) => { 10 if (value === undefined) { 11 return null; 12 } 13 if (typeof value === 'function') { 14 return Function.prototype.toString.call(value); 15 } 16 return value; 17 } 18 let jsonS = JSON.stringify(data, rep); 19 //{"name":null,"age":18,"type":null,"fn":"()=>{\n return 999;\n }"} 20 let jsonR = JSON.parse(jsonS, (key, value)=>{ 21 if (key) { 22 // return eval('('+value+')'); 23 return new Function('return '+value)() 24 } 25 return value; 26 }); 27 console.log(jsonR, jsonR.fn()); 28 // { name: null, age: 18, type: null, fn: [Function] } 29 // 999
對於reviver 函數的處理用了eval 和 new Function 兩種方式,因為eval的安全性問題,並不推薦使用,優先使用後一種方式。
三、toJSON
如果有toJSON,執行 .stringify時會先執行這個方法,再執行第二個參數
toJSON 是一個覆蓋函數,要慎重使用。
1 let data = { 2 name: 'nan', 3 age: 18, 4 toJSON: function () { 5 console.log('to'); 6 return this.name; 7 } 8 }; 9 JSON.stringify(data, (key,value)=>{ 10 console.log('rep'); 11 return value; 12 }); 13 // to 14 // rep 15 // "nan"
總結:對象中儘量只存儲基礎數據類型,儘量避免以上幾種對於數據化不友好的類型。