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

Angular4+Ionic3对象深拷贝问题:子对象仍引用原对象

解决TypeScript/Angular4/Ionic3中嵌套对象的深拷贝问题

我完全懂你遇到的困扰——当你拷贝包含嵌套对象列表的Period数组时,浅拷贝只能复制顶层对象的引用,修改嵌套的Declaration子对象时,原数据也跟着变了。这是因为你尝试的Object.assign本质是浅拷贝,它只会复制第一层的属性值,对于深层的对象(比如declarations数组里的Declaration实例、Date类型),只会复制它们的引用,所以原对象和拷贝对象会共享这些深层数据。

下面给你几种可行的深拷贝方案,适配你的Period和Declaration类结构:

1. 手动实现递归深拷贝(推荐保留类实例时使用)

因为你的数据是自定义类的实例(Period、Declaration、FileCustom),如果直接用JSON序列化会丢失类的类型和可能存在的方法,手动写递归拷贝函数可以精准控制每个类的实例化:

import { Period } from './period.entity';
import { Declaration } from './declaration.entity';
import { FileCustom } from './file.entity';

function deepClone<T>(obj: T): T {
  // 处理原始类型和null/undefined
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // 处理Date类型(避免引用共享)
  if (obj instanceof Date) {
    return new Date(obj.getTime()) as T;
  }

  // 处理数组
  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item)) as unknown as T;
  }

  // 处理Period实例
  if (obj instanceof Period) {
    return new Period(
      obj.number,
      obj.status,
      obj.year,
      obj.month,
      obj.sum,
      obj.orderNumber,
      obj.userId,
      deepClone(obj.submitDate),
      obj.comment,
      deepClone(obj.declarations)
    ) as T;
  }

  // 处理Declaration实例
  if (obj instanceof Declaration) {
    return new Declaration(
      obj.id,
      obj.status,
      obj.name,
      obj.description,
      obj.amount,
      deepClone(obj.date),
      deepClone(obj.period),
      obj.userId,
      deepClone(obj.files),
      obj.comment
    ) as T;
  }

  // 处理FileCustom实例(根据你的FileCustom结构调整)
  if (obj instanceof FileCustom) {
    return new FileCustom(
      obj.id, // 假设FileCustom有id字段
      obj.name, // 假设FileCustom有name字段
      // 其他字段按需添加,需要深拷贝的字段调用deepClone
    ) as T;
  }

  // 处理普通对象(兜底)
  const clonedObj = {} as T;
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      clonedObj[key] = deepClone(obj[key]);
    }
  }
  return clonedObj;
}

使用方式:

const clonedPeriods = deepClone(this.periods);

这样拷贝后的clonedPeriods里的所有嵌套对象都是全新的实例,修改它们的属性不会影响原periods数组。

2. JSON序列化反序列化(简单但有局限性)

如果你的类只是纯数据模型,没有自定义方法,这个方法最快捷:

const clonedPeriods = JSON.parse(JSON.stringify(this.periods)) as Period[];

⚠️ 注意局限性:

  • Date对象会被转成ISO字符串,之后需要手动转回Date类型(比如遍历拷贝后的数组,把submitDate、date字段重新实例化为new Date(...))
  • 自定义类的实例会变成普通的JavaScript对象,不再是Period/Declaration的实例,如果之后需要调用类的方法会报错
  • 无法处理循环引用(如果你的对象之间有互相引用的情况)

3. 使用第三方库(lodash.cloneDeep)

如果你项目允许引入第三方库,lodash的cloneDeep方法能完美处理大部分深拷贝场景,包括自定义类、Date、数组等:

首先安装依赖:

npm install lodash.clonedeep --save

然后导入使用:

import cloneDeep from 'lodash.clonedeep';

const clonedPeriods = cloneDeep(this.periods);

这个方法省心省力,不需要自己写递归逻辑,而且能保留类的原型链(如果你的类有继承关系也能处理)。


内容的提问来源于stack exchange,提问作者Niek Jonkman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:22:45