JSON.stringify()和JSON.parse() 的使用总结
JSON.stringify
语法
代码语言:javascript复制JSON.stringify(value[, replacer [, space]])
参数
value
- 将要序列化成 一个
JSON
字符串的值。
- 将要序列化成 一个
replacer
(可选)- 如果该参数是一个「函数」,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理。
- 如果该参数是一个「数组」,则只有包含在这个数组中的属性名才会被序列化到最终的
JSON
字符串中。 - 如果该参数为
null
或者未提供,则对象所有的属性都会被序列化。
space
(可选)- 指定缩进用的空白字符串,用于美化输出(pretty-print)。
- 如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格。
- 如果该参数为字符串(当字符串长度超过10个字母,取其前10个字母),该字符串将被作为空格。
- 如果该参数没有提供(或者为 null),将没有空格。
返回值
一个表示给定值的JSON
字符串。
异常
- 当在循环引用时会抛出异常
TypeError
("cyclic object value")(循环对象值) - 当尝试去转换
BigInt
类型的值会抛出TypeError
("BigInt value can't be serialized in JSON")(BigInt
值不能JSON
序列化)。
使用
代码语言:javascript复制JSON.stringify({}); // '{}'
JSON.stringify(true); // 'true'
JSON.stringify("foo"); // '"foo"'
JSON.stringify([1, "false", false]); // '[1,"false",false]'
JSON.stringify({ x: 5 }); // '{"x":5}'
// 使用第二个参数
let replacerFun = function (key, value) {
if (key === 'name') {
return undefined
}
return value
}
let user = {
name: '夏安',
age: 20,
id: '123'
}
JSON.stringify(user, replacerFun); // '{"age":20,"id":"123"}'
JSON.stringify(user, ["age"]); // '{"name":"夏安","id":"123"}'
// 为了便于使用 '--' 替代了空格
JSON.stringify(user, null, 2);
//{
//--"name": "夏安",
//--"age": 20,
//--"id": "123"
//}
特殊情况
toJSON 方法
如果一个被序列化的对象拥有 toJSON
方法,那么 toJSON
方法后的返回值会被序列化,例如:
var obj = {
foo: 'foo',
toJSON: function () {
return 'bar';
}
};
JSON.stringify(obj); // '"bar"'
JSON.stringify({x: obj}); // '{"x":"bar"}'
变为 null or 被忽略
- 在数组对象中,
undefined
、「任意的函数」以及symbol
值会被转换成null
JSON.stringify([undefined, Object, Symbol("")]); // '[null,null,null]'
- 在非数组对象中,
undefined
、「任意的函数」以及symbol
值在序列化的过程中会被忽略
JSON.stringify({x: undefined, y: Object, z: Symbol("")}); // '{}'
- 无论是数组对象还是非数组对象中,
NaN
和Infinity
会被转换成null
let user = {
name: '夏安',
age: Infinity,
id: NaN
}
JSON.stringify(user); // '{"name":"夏安","age":null,"id":null}'
JSON.stringify(['夏安', NaN, Infinity]); // '["夏安",null,null]'
- 不可枚举的属性默认会被忽略
JSON.stringify(
Object.create(
null,
{
x: { value: 'x', enumerable: false },
y: { value: 'y', enumerable: true }
}
)
);
// "{"y":"y"}"
这个时候第二个参数就可以发挥作用了:
代码语言:javascript复制JSON.stringify({x: undefined, y: Object, z: Symbol("")}, (key, value) => {
if (typeof value === 'undefined') {
return 'undefined'
} else if (typeof value === 'symbol' || typeof value === 'function') {
return value.toString()
}
return value
});
// '{"x":"undefined","y":"function Object() { [native code] }","z":"Symbol()"}'
undefined
undefined
、「任意的函数」以及 symbol
被 JSON.stringify()
作为单独的值进行序列化时都会返回 undefined
JSON.stringify(function a (){console.log('a')}); // undefined
JSON.stringify(undefined); // undefined
JSON.stringify(Symbol('dd')); // undefined
Date 对象
JSON.stringify()
将会正常序列化Date
的值。
JSON.stringify({ now: new Date() });
// '{"now":"2021-11-21T12:07:01.054Z"}'
实际上 Date
对象内置了 toJSON()
方法(同Date.toISOString()
),因此 Date
对象会被当做字符串处理。
JSON.parse
语法
代码语言:javascript复制JSON.parse(text[, reviver])
参数
text
- 要被解析成
JavaScript
值的字符串。
- 要被解析成
reviver
(可选)- 转换器, 如果传入该参数(函数),可以用来修改解析生成的原始值,调用时机在 parse 函数返回之前。
- 更具体点讲就是:解析值本身以及它所包含的所有属性,会按照一定的顺序(从最最里层的属性开始,一级级往外,最终到达顶层,也就是解析值本身)分别的去调用
reviver
函数,在调用过程中,当前属性所属的对象会作为this
值,当前属性名和属性值会分别作为第一个和第二个参数传入reviver
中。如果reviver
返回undefined
,则当前属性会从所属对象中删除,如果返回了其他值,则返回的值会成为当前属性新的属性值。 - **【注】**当遍历到最顶层的值(解析值)时,传入
reviver
函数的参数会是空字符串""
(因为此时已经没有真正的属性)和当前的解析值(有可能已经被修改过了),当前的this
值会是{"": 修改过的解析值}
返回值
Object
类型, 对应给定 JSON
文本的对象/值。
异常
若传入的字符串不符合 JSON
规范,则会抛出 SyntaxError
异常。
使用
代码语言:javascript复制JSON.parse('{}'); // {}
JSON.parse('true'); // true
JSON.parse('"foo"'); // "foo"
JSON.parse('[1, 5, "false"]'); // [1, 5, "false"]
JSON.parse('null'); // null
JSON.parse('{"p": 5}', function (k, v) {
if(k === '') return v; // 如果到了最顶层,则直接返回属性值,
return v * 2; // 否则将属性值变为原来的 2 倍。
}); // { p: 10 }
JSON.parse('{"1": 1, "2": 2,"3": {"4": 4, "5": {"6": 6}}}', function (key, value) {
console.log(key); // 输出当前的属性名,从而得知遍历顺序是从内向外的,
// 最后一个属性名会是个空字符串。
return value; // 返回原始属性值,相当于没有传递 reviver 参数。
});
// 1
// 2
// 4
// 6
// 5
// 3
// ""
使用场景
对象的深拷贝
代码语言:javascript复制let user = {
name: '夏安',
age: 20,
id: '123'
}
let user2 = JSON.parse(JSON.stringify(user));
user2.age = 66;
console.log(user.age); // 20
console.log(user2.age); //66
判断对象是否相等
代码语言:javascript复制JSON.stringify([1, 2, 3]) === JSON.stringify([1, 2, 3]);// true
localStorage/sessionStorage 存储对象
一些时候,你想存储用户创建的一个对象,并且,即使在浏览器被关闭后仍能恢复该对象。
我们知道 localStorage
/sessionStorage
只可以存储字符串,当我们想存储对象的时候,需要使用 JSON.stringify
转换成字符串,获取的时候再 JSON.parse
// 创建一个示例数据
var session = {
'screens' : [],
'state' : true
};
session.screens.push({"name":"screenA", "width":450, "height":250});
session.screens.push({"name":"screenB", "width":650, "height":350});
session.screens.push({"name":"screenC", "width":750, "height":120});
session.screens.push({"name":"screenD", "width":250, "height":60});
session.screens.push({"name":"screenE", "width":390, "height":120});
session.screens.push({"name":"screenF", "width":1240, "height":650});
// 使用 JSON.stringify 转换为 JSON 字符串
// 然后使用 localStorage 保存在 session 名称里
localStorage.setItem('session', JSON.stringify(session));
// 然后是如何转换通过 JSON.stringify 生成的字符串,该字符串以 JSON 格式保存在 localStorage 里
var restoredSession = JSON.parse(localStorage.getItem('session'));
// 现在 restoredSession 包含了保存在 localStorage 里的对象
console.log(restoredSession);
参考
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify