为何array.map会将类实例转为普通对象?求解决方法
问题描述
我有一个存储User类实例的Users[]数组,通过映射查询结果创建该数组,代码如下:
function GetUserByUserData(data : UserData[] | ReadonlyArray<UserData>) : User[] { return data.map((userData) => { return new User(userData); }); }
注:UserData是类型为{id: number; [key: string]: any;}的对象。
随后我通过方法基于类属性创建行,相关代码如下:
//User类 export default class User { private _data: UserData; get data() { return this._data; } }
let rows = Users.map((user) => makeRowFromUser(user)); function makeRowFromUser(user: User) { console.log(user); //输出 {_data} console.log(user.data); //输出 undefined console.log(user._data); //正常输出数据 }
我意识到私有属性_data本不应被直接访问,但实际可以;同时user.data返回undefined,console.log(user)显示其为{_data}格式的普通对象。
请问为何会出现这种情况?array.map是否解构了Users[]数组?user参数是否在传入函数前被解构?该如何避免此问题,确保传递的是User类实例?
补充:实际代码流程如下:
- 调用API获取用户;
- 查询数据库得到
unknown[],并转换为UserData[],代码如下:
function ConvertUknownResultToUserData(raw : unknown[]) : ReadonlyArray<UserData> { return raw.map<UserData>((e : any) : UserData => ({ id: e.user_id, name_first: e.name_first, name_last: e.name_last, //... })); }
- 通过
GetUserByUserData方法创建User[]; - 在Svelte组件中,Promise解析后映射
User[]生成行:
//Svelte组件内部... await window.api.GetUsers(). then((value) => { return value.map((user) => makeRowFromUser(user)); });
- 显示表格行。
问题出现在第4步,即API返回User[]之后。
问题分析与解决
核心原因
你的User实例在API传递过程中被序列化/反序列化成了普通JSON对象,而非类实例。类实例无法直接通过跨进程/API通信传递,序列化时会被转换成仅包含自身可枚举属性的普通对象(也就是你看到的{_data}):
user.data返回undefined:类的getter属于原型链方法,序列化后的普通对象没有继承User类的原型,自然访问不到这个getter属性。- 能直接访问
_data:TypeScript的private只是编译时检查,编译后的JavaScript中_data就是普通对象属性,没有真正的私有性限制。 array.map本身不会解构实例,问题出在API返回环节——window.api.GetUsers()返回的不是真正的User实例数组,而是序列化后再反序列化得到的普通对象数组。
解决方法
1. 补充User类的构造函数
你之前的User类缺少构造函数,导致new User(userData)时_data属性根本不会被赋值,这是潜在的关键问题,必须补上:
export default class User { private _data: UserData; // 新增构造函数 constructor(data: UserData) { this._data = data; } get data() { return this._data; } }
2. 在API接收端重新构建User实例
在Svelte组件中,拿到API返回的普通对象后,重新用User类包装:
//Svelte组件内部修改 await window.api.GetUsers().then((rawUsers) => { // 将普通对象转为User实例 const userInstances = rawUsers.map(userObj => new User(userObj._data)); return userInstances.map(user => makeRowFromUser(user)); });
3. (可选)给User类添加静态反序列化方法
可以封装一个静态方法,更优雅地从普通对象恢复实例:
export default class User { private _data: UserData; constructor(data: UserData) { this._data = data; } get data() { return this._data; } // 静态方法:从普通对象恢复实例 static fromObject(obj: {_data: UserData}): User { return new User(obj._data); } }
使用时:
await window.api.GetUsers().then((rawUsers) => { const userInstances = rawUsers.map(User.fromObject); return userInstances.map(user => makeRowFromUser(user)); });
内容的提问来源于stack exchange,提问作者Lae
相关产品推荐
相关产品推荐

