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
相关产品推荐
相关产品推荐

