TypeScript中如何合并类实例?扩展操作符丢失访问器问题
解决类实例合并/复制的问题
这个问题很典型——扩展运算符确实没法直接创建Person类的新实例,因为它的工作机制和类实例的结构不匹配。让我先拆解原因,再分享几个靠谱的解决办法:
为什么扩展运算符不行?
扩展运算符{...peter}只会拷贝对象的可枚举自有属性,但你的Person类有两个关键点:
age的getter/setter是定义在类的原型上的,不是实例的自有属性,所以扩展运算符不会拷贝这些访问器;_age是私有属性,外部无法直接访问,扩展运算符也拿不到这个值——你看到的age:30其实是通过getter读取到的结果,被当作普通属性复制到了新对象里。
最终得到的marc只是一个普通对象,原型链和Person无关,自然没有类的getter/setter逻辑。
解决办法
1. 手动创建新实例并赋值(简单直接)
如果类的属性不多,最直观的方式就是新建一个Person实例,手动复制原实例的属性,再修改需要调整的值:
let peter = new Person(); peter.age = 30; // 创建新实例并赋值 let marc = new Person(); marc.age = peter.age; // 通过getter读取peter的age,再通过setter赋值给marc marc.age = 20; // 正常触发setter
2. 给类添加copyWith方法(优雅可扩展)
如果类的属性较多,或者需要频繁复制实例,推荐给Person类添加一个专门的复制/合并方法,封装实例创建和属性赋值的逻辑:
class Person { private _age: number; get age(): number { return this._age; } set age(value: number) { this._age = value; } // 基于当前实例创建新实例,并覆盖传入的部分属性 copyWith(partial: { age?: number }): Person { const newInstance = new Person(); // 复制当前实例的所有属性 newInstance.age = this.age; // 覆盖传入的属性(如果有) if (partial.age !== undefined) { newInstance.age = partial.age; } return newInstance; } } // 使用方式 let peter = new Person(); peter.age = 30; let marc = peter.copyWith({ age: 20 }); // 直接得到带getter/setter的Person实例
这种方式还能灵活控制哪些属性允许被覆盖,后续添加新属性时只需要修改copyWith方法即可。
3. 用Object.assign赋值到新实例
Object.assign可以把源对象的可枚举属性赋值给目标对象,只要目标是Person实例,就会触发对应的setter:
let peter = new Person(); peter.age = 30; let marc = new Person(); Object.assign(marc, peter); // 自动调用marc的setter来设置age marc.age = 20; // 正常修改
注意:Object.assign同样只能访问到类对外暴露的属性(比如通过getter的age),私有属性_age不会被直接拷贝,但这符合类的封装设计——我们本来就应该通过setter/getter来操作属性。
内容的提问来源于stack exchange,提问作者Michael Hilus
相关产品推荐
相关产品推荐

