JSON.stringify() 和 JSON.parse() 用于序列化和解析。
JSON 的语法是js语法的子集,它并不能表示js里的所有值。支持对象、数组、字符串、数字、布尔值和null。NaN、Infinity和-Infinity 序列化的结果是 null,Date对象序列化的结果是ISO格式的日期字符串,但 JSON.parse() 依然保留它们的字符串形态,而不会将它们还原为原始日期对象。函数、RegExp、Error对象和 undefined 不能序列化和还原。JSON.stringify() 只能序列化对象可枚举的自有属性。对于一个不能序列化的属性来说,在序列化后的输出字符串中会将这个属性省略掉。JSON.stringify() 和 JSON.parse() 都可以接收第二个可选参数,通过传入需要序列化或还原的属性列表来定制自定义的序列化或还原操作。
JSON.parse(str, reviver)
第二个参数 reviver 用来转换解析值的可选函数。它会深度遍历对象的属性和数组,对对象的每个属性或数组的每个元素都执行一次 reviver 函数。reviver 函数带有2个参数:第一个参数是对象的属性名或转换成字符串的数组序号;第二个参数是对象属性或数组元素的值。
reviver 函数的返回值会成为属性的新值。如果 reviver 返回第二个参数,则该属性保持不变。如果 reviver 返回 undefined(或根本没有返回任何值),则会从对象或数组中删除该属性。
var obj = {
name: 'Jim',
age: 22,
person: {
boy: true,
gilr: 2
}
}
var json = JSON.parse(JSON.stringify(obj), function(key, value) {
console.log(key) // name age boy girl person ''
})
JSON.stringify() 详解
一、语法
JSON.stringify(value[, replacer [, indent]])
二、JSON.stringify() 实际使用场景
- 对象和数组的深拷贝
- 对 http 请求参数进行序列化
- 对要存储到 Storage 的数据转换成字符串
三、JSON.stringify() 的几个特性
第一大特性
对于 undefined、任意的函数以及 symbol 三个特殊的值分别作为对象属性的值、数组元素、单独的值时 JSON.stringify()将返回不同的结果。
1. 作为对象属性值时 JSON.stringify() 将跳过(忽略)对它们进行序列化
const data = {
a: "aaa",
b: undefined,
c: Symbol("dd"),
fn: function() {
return true;
}
};
JSON.stringify(data);
// "{"a":"aaa"}"
2. 作为数组元素值时,JSON.stringify() 会将它们序列化为 null
JSON.stringify(["aaa", undefined, function aa() {
return true
}, Symbol('dd')])
// "["aaa",null,null,null]"
3. 作为单独的值进行序列化时都会返回 undefined
第二大特性
被转换值如果有 toJSON()
函数,该函数返回什么值,序列化结果就是什么值,并且忽略其他属性的值。
JSON.stringify({
say: "hello JSON.stringify",
toJSON: function() {
return "today i learn";
}
})
// "today i learn"
第三大特性
会把 Date 自动转成 ISO 格式
JSON.stringify({ now: new Date() });
// "{"now":"2019-12-08T07:42:11.973Z"}"
实际上 Date 对象自己部署了 toJSON() 方法(同Date.toISOString()),因此 Date 对象会被当做字符串处理。
第四大特性
NaN 和 Infinity 格式的数值及 null 都会被当作 null。
JSON.stringify(NaN)
// "null"
JSON.stringify(null)
// "null"
JSON.stringify(Infinity)
// "null"
第五大特性
对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会报错。
const obj = {
name: "loopObj"
};
const loopObj = {
obj
};
// 对象之间形成循环引用,形成闭环
obj.loopObj = loopObj;
JSON.parse(JSON.stringify(obj); //报错
第六大特性
所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer
参数中强制指定包含了它们。
JSON.stringify({[Symbol("foo")]: "foo"});
// '{}'
第七大特性
数组里的 key value 值会被忽略。
let arr = ['a', 'b'];
arr.age = 22;
JSON.stringify(arr) // ["a","b"]
四、replacer 参数(用的少)
replacer 参数可以是一个函数或者一个数组。作为函数,它有两个参数,键(key)和值(value),它们都会被序列化。
需要注意的是,replacer 被传入的函数时,第一个参数不是对象的第一个键,而是空字符串作为 key 值,value 值是整个对象的键值对。
如果 replacer
是一个数组,数组的值代表将被序列化成 JSON 字符串的属性名。
const jsonObj = {
name: "JSON.stringify",
params: "obj,replacer,space"
};
// 只保留 params 属性的值
JSON.stringify(jsonObj, ["params"]);
// "{"params":"obj,replacer,space"}"
五、indent 参数
indent 参数可以指定缩进字符串或用来缩进的空格个数(最多10个空格或该字符串的前10个字符)。