现象:
-
最常见的实现
[object,object]对象序列化和反序列化的代码是JSON.stringify,但是JSON.stringify的缺点是:- 会忽略对象中的函数和undefined值以及
Symbol的值,在序列化后会自动删除这部分的值 -
const sym = Symbol('example') const obj = { name:'John', getName:function(){ return this.name; }, [sym]:'value', undeStr:undefined } console.log(JSON.stringify(obj))//{"name":"John"} - 针对循环引用的代码会显示错误
-
const obj1 = {} const obj2 = { ref:obj1 } obj1.ref = obj2 try{ const a = JSON.stringify(obj1) }catch(error){ console.log('error'+error.message) } - 针对某些特殊的
object对象会没有办法解析,会改变其值变成string对象 -
const obj = { ref0:new Date() } console.log(JSON.stringify(obj))//{"ref0":"2025-05-09T01:23:02.236Z"}
- 会忽略对象中的函数和undefined值以及
解决办法:
-
针对以上的
JSON.stringify的解决办法,可以引入SuperJSON这个库,去进一步封装以用于适应自己的项目,SuperJSON的好处:- 可以很好处理上面的JSON.stringify和JSON.parse的问题
- 对于TS友好,针对于数据类型不会将所有未知/自定义的数据类型转成any
- 支持懒加载对于大型的json数据,可以实现懒加载配置
SuperJSON的工作:
- 为部分常见的特殊类型添加类型标记,以便在反序列化的时候恢复原始类型,比如
Date类型 - 针对部分的自己预定义的类型,根据原型链注册转换器,
isApplicable:判断值是否属于目标类型;serialize:将值转换为 JSON 兼容格式;deserialize:从 JSON 数据恢复原始类型。
//针对常见的特殊类型会自动建立标记
{
"superjson":{
"type":"Date",
"value":"2025-05-09T00:00:00.000Z"
}
}
class Point {
constructor(public x: number, public y: number) {}
}
//项目注册相关自定义类型,即可使用
SuperJSON.registerCustom(
{
isApplicable: (value): value is Point => value instanceof Point,
serialize: (point) => ({ x: point.x, y: point.y }),
deserialize: (data) => new Point(data.x, data.y)
},
'Point' // 类型标识符
);
实际应用案例:
- localstorage和sessionstorage一般都只能接受json字符串的存储格式。
- 后端传的数据可能为了保持实时性,传的是Date或者正则等格式的数据
- 可能在某些场景上,数据是存在循环应用的case