Basic knowledge of
The following information from MDN is relatively comprehensive and easy to understand
define
The json.stringify () method converts a JavaScript object or value to a JSON string, optionally replacing the value if a replacer function is specified, or optionally containing only the properties specified by the array if the specified replacer is an array.
grammar
JSON.stringify(value[, replacer [, space]])
Copy the code
parameter
value
The value to be serialized into a JSON string.
replacer optional
If the parameter is a function, each attribute of the serialized value is converted and processed by the function during serialization;
If the parameter is an array, only the property names contained in the array will be serialized into the final JSON string;
If this parameter is null or not provided, all attributes of the object are serialized.
space optional
Specifies a blank string for indentation, which is used to beautify the output (pretty-print).
If the argument is a number, it represents how many Spaces there are; The upper limit is 10. If the value is less than 1, there are no Spaces. If the parameter is a string (the first 10 characters are taken when the string is longer than 10 characters), the string will be used as a space.
If this parameter is not provided (or null), there will be no Spaces.
Value is commonly used. Replacers can be customized as required.
The return value
A JSON string representing the given value
abnormal
- When in
A circular reference
Will throw an exception TypeError (” Cyclic Object Value “) - When trying to switch
BigInt
Type values will raise TypeError (“BigInt value can’t be serialized in JSON”).
features
Features a
1. Undefined, arbitrary functions, and symbol values are ignored during serialization (when they appear in property values of non-array objects) or converted to NULL (when they appear in arrays).
2. Properties of non-array objects are not guaranteed to appear in a serialized string in a particular order
const obj = {
a: 1.b: undefined.// ignore
c: '11'.d() {
console.log('this is func');
}, // ignore
e: Symbol('tadm') // ignore
}
console.log(JSON.stringify(obj));
// {"a":1,"c":"11"}
console.log(JSON.stringify([1.'11'.undefined.() = > 1 + 1.Symbol('tadm')));// [1,"11",null,null,null]
Copy the code
3. Function/undefined returns undefined when converted separately
console.log(JSON.stringify(undefined));
// undefined
console.log(JSON.stringify(() = > 1 + 1));
// undefined
Copy the code
4.NaN and Infinity values and null are treated as null
console.log(JSON.stringify(NaN));
// null
console.log(JSON.stringify(Infinity));
// null
console.log(JSON.stringify(null));
// null
Copy the code
Features two
If there is a toJSON() method, which defines what values will be serialized and ignores other attribute values
console.log(JSON.stringify({
name: 'toJSON'.toJSON: () = > console.log('this is toJSON')}));// this is toJSON
console.log(JSON.stringify({
name: 'toJSON'.toJSON: () = > console.log('this is toJSON'),
toJSON: () = > 1 + 1,}));/ / 2
Copy the code
Features three
Booleans, numbers, and string wrapper objects are automatically converted to their original values during serialization
console.log(JSON.stringify(new Boolean(true)));
// true
console.log(JSON.stringify(new Number(1)));
/ / 1
console.log(JSON.stringify(new String('tadm')));
// "tadm"
Copy the code
Features four
Executing this method on objects that contain circular references (objects that refer to each other in an infinite loop) throws an error
const obj = {
a: 1,
}
obj.b = obj;
console.log(JSON.stringify(obj));
// TypeError: Converting circular structure to JSON
// --> starting at object with constructor 'Object'
// --- property 'f' closes the circle
Copy the code
Features five
Date the Date is converted to a string by calling toJSON() (same as date.toisostring ()), so it is treated as a string
const date = new Date(a);console.log(JSON.stringify(date), date.toISOString());
/ / "the 2021-10-14 T07: far. 112 z" 2021-10-14 T07: far. 112 z
Copy the code
Features 6
All properties with symbol as the property key are completely ignored, even if they are mandatory in the replacer parameter
Copy the code
Features seven
Other types of objects, including Map/Set/WeakMap/WeakSet, serialize only enumerable properties
const a = new Map(a); a.set('x'.1);
console.log(a, '-- -- -- -- -- -.JSON.stringify(a));
// Map(1) { 'x' => 1 } ------ {}
// All other effects are the same
const obj = Object.create(null, {
x: { value: 1 },
y: { value: 2.enumerable: true}});console.log(Object.getOwnPropertyDescriptors(obj));
/** * { x: { value: 1, writable: false, enumerable: false, configurable: false }, y: { value: 2, writable: false, enumerable: true, configurable: false } } **/
console.log(JSON.stringify(obj));
// {"y":2}
Copy the code
Features eight
An error is also thrown when converting BigInt
JSON.stringify(BigInt('666'))
// Uncaught TypeError: Do not know how to serialize a BigInt
Copy the code
Use the advanced
replacer
function
const foo = {
foundation: "Mozilla".model: "box".week: 45.transport: "car".month: 7
};
const replacer = (key, value) = > {
if (typeof value === "string") {
return undefined;
}
return value;
}
console.log(JSON.stringify(foo, replacer));
// {"week":45,"month":7}
Copy the code
An array of
console.log(JSON.stringify(foo, ['foundation'.'transport']));
// {"foundation":"Mozilla","transport":"car"}
Copy the code
space
console.log(JSON.stringify(foo, null.2)); // Display two Spaces
/** * { "foundation": "Mozilla", "model": "box", "week": 45, "transport": "car", "month": 7 } **/
Copy the code
Source analysis
If you don’t call toString(), you’ll call toString()
implementation
const stringify = (data) = > {
const isCyclic = (obj) = > {
let set = new Set(a);let flag = false;
const deep = (obj) = > {
if (obj && typeofobj ! ='object') {
return;
}
if (set.has(obj)) {
return flag = true;
}
set.add(obj);
// Fix object.create (null)
if(! obj? .hasOwnProperty) { obj.hasOwnProperty =new Object().hasOwnProperty;
}
for (let key in obj) {
if(obj.hasOwnProperty(key)) { deep(obj[key]); }}// Get rid of it
set.delete(obj);
}
deep(obj);
return flag;
}
if (isCyclic(data)) {
throw new TypeError('Converting circular structure to JSON');
}
if (typeof data === 'bigint') {
throw new TypeError('Do not know how to serialize a BigInt');
}
const type = typeof data;
const commonKeys1 = ['undefined'.'function'.'symbol'];
const commonKeys2 = [NaN.Infinity.null];
const getType = (s) = > {
return Object.prototype.toString.call(s).replace(/\[object (.*?)\]/.'$1').toLowerCase()
};
if(type ! = ='object' || data === null) {
let result = data;
if (commonKeys2.includes(data)) {
result = null;
} else if (commonKeys1.includes(type)) {
return undefined;
} else if (type === 'string') {
result = `"${data}"`;
}
return String(result);
} else if (type === 'object') {
// The object itself has toJSON methods
if (typeof data.toJSON === 'function') {
// Return the result and execute the above process
return stringify(data.toJSON());
} else if (Array.isArray(data)) {
let result = data.map((it) = > {
return commonKeys1.includes(typeof it) ? 'null' : stringify(it);
})
return ` [${result}] `.replace(/'/g.'"');
} else {
// Wrap objects for booleans, numbers, and strings
if (['boolean'.'number'].includes(getType(data))) {
return String(data);
} else if (getType(data) === 'string') {
return `"${data}"`;
} else {
let result = [];
// iterate over all keys
Object.keys(data).forEach((key) = > {
if (typeofkey ! = ='symbol') {
const value = data[key];
if(! commonKeys1.includes(typeof value)) {
// Note that if value is still an object, recursive processing is required
result.push(`"${key}":${stringify(value)}`)}}})return ` {${result}} `.replace(/ / '.'"'); }}}}Copy the code
test
console.log(stringify({
toJSON: () = > 1 + 1
}))
/ / 2
const obj = {
a: 1.b: undefined.c: '11'.d() {
console.log('this is func');
},
e: Symbol('tadm'),
// g: BigInt('666')
}
// obj.f = obj;
const obj = Object.create(null, {
x: { value: 1 },
y: { value: 2.enumerable: true}});console.log(stringify(obj));
// {"a":1,"c":"11"}
// {"y":2}
Copy the code
End
Json. stringify is just one of many apis that we use to manipulate objects, such as localStorage, because it can only store strings, we can just convert objects to strings. However, as mentioned above, it is easy to ignore the conversion results of non-normal data (undefined, null, BigInt, etc.), so be careful when using these features.