这不是一个新话题,但有一个新的解决方案:现代方法(2021 年 12 月)是使用@badcafe/jsonizer
:https ://badcafe.github.io/jsonizer
- 与其他解决方案不同,它不会用注入的类名污染您的数据,
- 它具体化了预期的数据层次结构。
- 以下是 Typescript 中的一些示例,但它在 JS 中也同样适用
在展示一个类的例子之前,让我们从一个简单的数据结构开始:
const person = {
name: 'Bob',
birthDate: new Date('1998-10-21'),
hobbies: [
{ hobby: 'programming',
startDate: new Date('2021-01-01'),
},
{ hobby: 'cooking',
startDate: new Date('2020-12-31'),
},
]
}
const personJson = JSON.stringify(person);
// {
// "name": "Bob",
// "birthDate": "1998-10-21T00:00:00.000Z",
// "hobbies": [
// {
// "hobby": "programming",
// "startDate": "2021-01-01T00:00:00.000Z"
// },
// {
// "hobby": "cooking",
// "startDate": "2020-12-31T00:00:00.000Z"
// }
// ]
// }
// store or send the data
请注意,日期被序列化为字符串,如果您解析该 JSON,日期将不是Date
实例,它们将是String
s
现在,让我们使用 Jsonizer
// in Jsonizer, a reviver is made of field mappers :
const personReviver = Jsonizer.reviver<typeof person>({
birthDate: Date,
hobbies: {
'*': {
startDate: Date
}
}
});
const personFromJson = JSON.parse(personJson, personReviver);
JSON 文本中的每个日期字符串都已映射到Date
解析结果中的对象。
Jsonizer 可以用递归嵌套的自定义类、第三方类、内置类或子 JSON 结构(数组、对象)无差别地恢复 JSON 数据结构(数组、对象)或类实例。
现在,让我们改用一个类:
// in Jsonizer, a class reviver is made of field mappers + an instance builder :
@Reviver<Person>({ // bind the reviver to the class
'.': ({name, birthDate, hobbies}) => new Person(name, birthDate, hobbies), // instance builder
birthDate: Date,
hobbies: {
'*': {
startDate: Date
}
}
})
class Person {
constructor( // all fields are passed as arguments to the constructor
public name: string,
public birthDate: Date
public hobbies: Hobby[]
) {}
}
interface Hobby {
hobby: string,
startDate: Date
}
const person = new Person(
'Bob',
new Date('1998-10-21'),
[
{ hobby: 'programming',
startDate: new Date('2021-01-01'),
},
{ hobby: 'cooking',
startDate: new Date('2020-12-31'),
},
]
);
const personJson = JSON.stringify(person);
const personReviver = Reviver.get(Person); // extract the reviver from the class
const personFromJson = JSON.parse(personJson, personReviver);
最后,让我们使用 2 个类:
@Reviver<Hobby>({
'.': ({hobby, startDate}) => new Hobby(hobby, startDate), // instance builder
startDate: Date
})
class Hobby {
constructor (
public hobby: string,
public startDate: Date
) {}
}
@Reviver<Person>({
'.': ({name, birthDate, hobbies}) => new Person(name, birthDate, hobbies), // instance builder
birthDate: Date,
hobbies: {
'*': Hobby // we can refer a class decorated with @Reviver
}
})
class Person {
constructor(
public name: string,
public birthDate: Date,
public hobbies: Hobby[]
) {}
}
const person = new Person(
'Bob',
new Date('1998-10-21'),
[
new Hobby('programming', new Date('2021-01-01')),
new Hobby('cooking', new Date('2020-12-31')
]
);
const personJson = JSON.stringify(person);
const personReviver = Reviver.get(Person); // extract the reviver from the class
const personFromJson = JSON.parse(personJson, personReviver);