如何通过WebSocket传递自定义类对象并调用其方法?
问题原因与解决方案
核心原因
JSON.stringify()只能序列化对象的可枚举自有属性,类的方法(比如add())是挂载在类的原型链上的,不会被序列化。当客户端解析JSON后得到的只是一个普通JavaScript对象,和Digit类没有原型链关联,自然找不到add()方法。
解决方法
方法1:客户端重建类实例
在客户端也定义完全相同的Digit类,将服务端传来的普通对象的属性赋值给新的类实例:
服务端代码:
// 直接序列化实例的自有属性即可 WS.send(JSON.stringify(C));
客户端代码:
// 客户端必须定义和服务端一致的Digit类 class Digit { constructor(data) { // 把服务端传来的属性赋值给当前实例 Object.assign(this, data); } add() { // 实现和服务端相同的方法逻辑 } } // 接收消息并处理 ws.onmessage = function(event) { const rawData = JSON.parse(event.data); // 用普通对象重建Digit实例 const C = new Digit(rawData); // 现在可以正常调用add() C.add(); };
方法2:添加类标识,客户端按需重建
在服务端序列化时给对象添加一个类类型标记,客户端根据标记判断并重建对应类的实例:
服务端代码:
// 给序列化对象添加类型标识 const serializedData = JSON.stringify({ __type__: 'Digit', ...C // 展开实例的所有自有属性 }); WS.send(serializedData);
客户端代码:
class Digit { constructor(data) { Object.assign(this, data); } add() { /* 方法逻辑 */ } } ws.onmessage = function(event) { const obj = JSON.parse(event.data); let instance; // 根据类型标识判断并重建实例 if (obj.__type__ === 'Digit') { delete obj.__type__; // 移除类型标记,避免污染实例 instance = new Digit(obj); } instance.add(); // 正常调用方法 };
方法3:自定义类的序列化逻辑
在Digit类中定义toJSON()方法,主动控制序列化的内容,避免手动拼接:
服务端代码:
class Digit { constructor(value) { this.value = value; // 假设实例有这个业务属性 } add() { /* 方法逻辑 */ } // 自定义序列化规则 toJSON() { return { __type__: 'Digit', value: this.value }; } } // 直接序列化实例即可 WS.send(JSON.stringify(new Digit(10)));
客户端处理逻辑和方法2一致,根据__type__标记重建实例即可。
注意事项
- 客户端必须保持
Digit类的定义和服务端一致(包括方法逻辑),可以把类抽成公共JS文件,让服务端和客户端共用,避免重复代码。 - 不要尝试直接序列化类的方法:JSON不支持函数类型的序列化,强行转换会把函数变成字符串,无法直接调用,同时也存在安全风险。
内容的提问来源于stack exchange,提问作者MahjongLover902012039
相关产品推荐
相关产品推荐

