javascript构造函数需手动实现序列化与反序列化:通过tojson()返回纯数据对象(含__type标识),再由静态fromjson()或注册表工厂方法重建实例,分离数据与行为,但无法还原闭包、循环引用等。

JavaScript 中构造函数本身不能直接序列化,因为 JSON.stringify() 只处理纯数据(对象的可枚举自有属性),会忽略方法、原型链、闭包、Symbol 键等。要实现基于构造函数的序列化与反序列化,需**手动约定数据结构 + 显式还原逻辑**,核心是分离“数据”和“行为”。
1. 序列化:只保留可重建实例的关键数据
在构造函数实例上定义一个 toJSON() 方法(会被 JSON.stringify() 自动调用),返回一个 plain object,仅包含能用于重建状态的字段:
- 避免包含函数、this 绑定、DOM 节点、Date 对象(应转为字符串)、RegExp 等不可序列化值
- 若需保存 Date,统一转为 ISO 字符串;RegExp 可存
pattern和flags - 可添加类型标识字段(如
__type: 'User'),便于反序列化时选择对应构造函数
示例:
class User {
constructor(name, age, createdAt) {
this.name = name;
this.age = age;
this.createdAt = createdAt || new Date();
}
toJSON() {
return {
__type: 'User',
name: this.name,
age: this.age,
createdAt: this.createdAt.toISOString()
};
}
}
const user = new User('Alice', 30);
const json = JSON.stringify(user); // {"__type":"User","name":"Alice","age":30,"createdAt":"2024-05-20T10:22:33.123Z"}
2. 反序列化:根据数据重建实例并恢复行为
不能直接用 JSON.parse() 得到实例(它只返回普通对象)。需编写一个工厂函数或静态方法,根据 __type 字段选择构造函数,并用解析后的数据初始化新实例:
- 先
JSON.parse()得到原始对象 - 检查
__type字段,映射到对应类(注意:类必须在作用域中可访问) - 用解构或参数传递方式调用构造函数(推荐使用 Object.assign 或构造函数参数重映射)
- 对特殊字段(如日期字符串)做类型还原
示例:
class User {
// ... 同上
static fromJSON(data) {
if (!data || data.__type !== 'User') throw new Error('Invalid User JSON');
return new User(
data.name,
data.age,
new Date(data.createdAt)
);
}
}
const obj = JSON.parse(json);
const restored = User.fromJSON(obj); // 真正的 User 实例,有原型方法
3. 支持多类型时的通用反序列化器
当项目中有多个带序列化能力的类时,可维护一个注册表,统一管理反序列化逻辑:
- 每个类注册自己的
fromJSON静态方法,并在全局 registry 中声明类型名 - 提供一个
deserialize(json)函数,自动识别类型并委托给对应类 - 避免
eval或new Function—— 安全且可控
示例:
const Deserializer = {
registry: {},
register(typeName, fromJSONFn) {
this.registry[typeName] = fromJSONFn;
},
deserialize(json) {
const data = JSON.parse(json);
const Ctor = this.registry[data.__type];
if (!Ctor) throw new Error(`Unknown type: ${data.__type}`);
return Ctor(data);
}
};
Deserializer.register('User', User.fromJSON);
// 使用
const restored = Deserializer.deserialize(json);
4. 注意边界情况与限制
这种模式不是万能的,需清醒认识其局限性:
-
无法还原闭包状态:构造函数中通过闭包捕获的私有变量(如 `const privateField = ...`)不会被
toJSON捕获,也无法反向注入 - 原型方法不参与序列化:这是设计使然,也是优点——序列化结果小、安全、跨语言友好
-
循环引用需额外处理:默认
JSON.stringify会报错,可用自定义 replacer 或第三方库(如flatted) -
继承关系需显式处理:子类
toJSON应调用super.toJSON()并合并自身字段;fromJSON也需按继承链逐级还原
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











