之前没有系统的学习 JSON.stringify,一次事故才发现我对 JSON.stringify 了解的还不够,特别是它对 undefined、function、Symbol、Date 等类型的处理。
1. JSON.stringify 函数定义
interface JSON {
/**
* Converts a JavaScript Object Notation (JSON) string into an object.
* @param text A valid JSON string.
* @param reviver A function that transforms the results. This function is called for each member of the object.
* If a member contains nested objects, the nested objects are transformed before the parent object is.
*/
parse(text: string, reviver?: (this: any, key: string, value: any) => any): any;
/**
* Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
* @param value A JavaScript value, usually an object or array, to be converted.
* @param replacer A function that transforms the results.
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
*/
stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
/**
* Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
* @param value A JavaScript value, usually an object or array, to be converted.
* @param replacer An array of strings and numbers that acts as an approved list for selecting the object properties that will be stringified.
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
*/
stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
}
JSON.stringify(value[, replacer [, space]])
2. JSON.stringify 8个细节
(1)转换值如果有 toJSON() 方法,该方法定义什么值将被序列化。
如果一个被序列化的对象拥有 toJSON 方法,那么该 toJSON 方法就会覆盖该对象默认的序列化行为:不是该对象被序列化,而是调用 toJSON 方法后的返回值会被序列化,例如:
var obj = {
foo: 'foo',
toJSON: function () {
return 'bar';
}
};
JSON.stringify(obj); // '"bar"'
JSON.stringify({x: obj}); // '{"x":"bar"}'
(2)布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值
console.log(JSON.stringify([new Number(3), new String('false'), new Boolean(false)]));
// expected output: "[3,"false",false]"
(3)undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。函数、undefined 被单独转换时,会返回 undefined,如JSON.stringify(function(){}) or JSON.stringify(undefined)。
console.log(JSON.stringify({
x: undefined,
y: 6,
z: function () {},
e: Symbol('e')
}));
// {"y":6}
console.log(JSON.stringify([undefined, 6, function() {}, Symbol('e')]))
// [null,6,null,null]
console.log(JSON.stringify(undefined))
// undefined
console.log(JSON.stringify(function(){}))
// undefined
(4) 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
var o = {}
o.self = o;
console.log(JSON.stringify(o))
Uncaught TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
--- property 'self' closes the circle
at JSON.stringify (<anonymous>)
(5) 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
JSON.stringify({[Symbol("foo")]: "foo"});
// '{}'
(6) Date 日期调用了 toJSON() 将其转换为 string 字符串(Date.toISOString()),因此会被当做字符串处理。
var o = {
date: new Date()
}
console.log(JSON.stringify(o))
// {"date":"2021-09-05T07:42:05.512Z"}
(7) NaN 和 Infinity 格式的数值及 null 都会被当做 null。
var o = {
date: NaN
}
console.log(JSON.stringify(o))
// {"date":null}
(8) 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。
var o = Object.create(
null,
{
x: { value: 'x', enumerable: false },
y: { value: 'y', enumerable: true },
}
)
console.log(JSON.stringify(o))
// {"y":"y"}
3. 使用 replacer 过滤属性
- 如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;
- 如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;
- 如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。
<script>
function replacer(key, value) {
if (typeof value === "string") {
return undefined;
}
return value;
}
var foo = {
foundation: "Mozilla",
model: "box",
week: 45,
transport: "car",
month: 7
};
// 函数测试
var jsonString = JSON.stringify(foo, replacer);
console.log(jsonString) // {"week":45,"month":7}
// 数组测试
JSON.stringify(foo, ['week', 'month']); // '{"week":45,"month":7}'
</script>
4. 使用 spacer 来美化输出
space 参数用来控制结果字符串里面的间距。
- 如果是一个数字, 则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多10个空格);
- 如果是一个字符串,则每一级别会比上一级别多缩进该字符串(或该字符串的前10个字符)。
var r = JSON.stringify({
a: 2,
b: {
a: 4
}
}, null, 2);
console.log(r)
/*{
"a": 2,
"b": {
"a": 4
}
}*/
网友评论