There are many scenarios that used JSON before, but they haven't been studied carefully. In recent days, I took advantage of a requirement to sort out the relevant usage.
I. JSON.stringify()
1. Syntax JSON. Stringify (value [, replace [, space]])
2. Let's talk about the next two optional parameters
space: it is a blank string for specifying indentation, which is used to beautify the output. It can be a number or a string.
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 // }
Replace: conversion rule, which can be a function or an array.
1 // 1. array 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. function 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
The value to be serialized into a JSON string. There are some types that cannot be converted. undefined/function/symbol
1). undefined
When JSON.stringify encounters undefined, it cannot be returned, but null is OK, so my treatment here is to convert undefined to null
The reason for this is because undefined == null //true, so the processed data does not affect the fuzzy judgment.
2). function
It's also a type that can't be returned. My processing is to convert it to string type storage. One of the problems caused by this is that when JSON.parse is used, it needs to be converted to function again
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 is a new data type, which is reserved for another article. Let's talk about JSON here.
1 // When value yes Symbol Can be specified by the second parameter. If it is not specified, it cannot be returned 2 // When key yes Symbol The second parameter cannot be specified 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'; //Only specified here can return results 10 return value; 11 }); 12 //{"name":"aaa","symbol":"symbol"}
If the value is Symbol, it can be converted by the second parameter; however, if the key is Symbol, it cannot be traversed and returned during traversal, similar to non enumeration type:
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"}
2. JSON.parse()
1. Syntax: JSON.parse(text[, reviver])
2. Parameter: reviver converter. If this parameter (function) is passed in, it can be used to modify the original value generated by parsing. The call time is before the return of the 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 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
eval and new Function are used to deal with the reviver function. Because of the security problem of eval, it is not recommended to use the latter method first.
Three, toJSON
If there is a toJSON, this method will be executed before the second parameter when executing. stringify
toJSON is an override function, which should be used with caution.
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"
Summary: only basic data types are stored in the object as far as possible, and the above types that are not friendly to data are avoided as far as possible.