You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中如何合并类实例?扩展操作符丢失访问器问题

解决类实例合并/复制的问题

这个问题很典型——扩展运算符确实没法直接创建Person类的新实例,因为它的工作机制和类实例的结构不匹配。让我先拆解原因,再分享几个靠谱的解决办法:

为什么扩展运算符不行?

扩展运算符{...peter}只会拷贝对象的可枚举自有属性,但你的Person类有两个关键点:

  1. age的getter/setter是定义在类的原型上的,不是实例的自有属性,所以扩展运算符不会拷贝这些访问器;
  2. _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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:20:21