如何将带自定义类方法的JavaScript对象存入MongoDB且不丢失方法
方法丢失是完全正常的行为
这不是代码bug,和你的实现逻辑对错无关,现象是由两个独立环节的运行机制共同决定的:
Socket.io传输环节就已经丢失了所有原型方法
Socket.io在跨网络传输数据时,会对发送的对象做结构化序列化(序列化规则和原生JSON.stringify完全一致),整个过程只会提取对象的可枚举自有属性:
- 你挂在
MyObject.prototype上的myMethod属于原型链上的属性,根本不属于实例本身的自有属性,序列化时会被完全忽略 - 哪怕是直接挂在实例上的函数类型属性,序列化时也会被丢弃——序列化逻辑不支持函数、Symbol这类非结构化数据的传输
也就是说,服务端在socket.on('updateSend')回调里拿到的object1,从接收完成的那一刻起,就已经不是MyObject的实例了,只是一个不携带任何类方法的普通纯对象。
Mongoose/MongoDB存储环节也不会保留函数和原型信息
就算你绕过Socket.io,在服务端本地直接new一个MyObject实例存进数据库,读取时方法依然会丢失:
- MongoDB存储的BSON格式只支持纯结构化数据(字符串、数字、数组、普通嵌套对象、日期等),根本不支持函数、类原型这类依赖JS运行时的非结构化信息
- 你当前的Schema定义没有问题,哪怕换成Mongoose更规范的数组定义
arrayData: [{}],也不会改变这个结果——Mongoose的Object类型字段在写入时,会把传入对象里的所有函数属性静默过滤,最终存进数据库的只是纯数据结构,读出来的结果自然没有任何类方法。
可行的解决思路
跨网络传输、落库存储的本质都是搬运可序列化的纯数据,不可能完整保留JS内存里的类实例运行时状态,常见的实现方式有两种:
- 只存对象的纯数据字段,需要使用时手动还原成类实例。比如从数据库/Socket拿到纯数据对象后,把对象的原型指回自定义类的原型,就可以正常调用类上的方法:
// 拿到纯数据对象后手动还原实例 const rawData = project.arrayData[0] const myInstance = Object.create(MyObject.prototype) Object.assign(myInstance, rawData) // 现在myInstance就可以正常调用myMethod了 - 把类上的自定义逻辑抽成独立的纯函数,不绑定在实例对象上。需要处理数组里的数据时,直接把对应的纯数据对象作为参数传入函数即可,不需要依赖对象本身的方法。
注意:不要尝试把函数类型的属性直接存入Mongoose字段,MongoDB原生不支持存储函数数据,写入时会被直接过滤甚至抛出异常,从设计上就不可能通过存函数的方式保留方法。
内容的提问来源于stack exchange,提问作者Hugo Aliaga Aguilar
相关产品推荐
相关产品推荐

