如何深度克隆带原型链的对象?structuredClone无法实现
如何克隆对象树并保留原型链?
structuredClone确实无法保留对象的原型链,它只会克隆对象的自有数据属性,不会继承原对象的原型方法。就像你给出的示例:
class Some { hi() { return 'hi' } } const a = new Some() console.log(a.hi()) const b = structuredClone(a) console.log(b.hi()) // => TypeError: b.hi is not a function
克隆后的b只是一个普通对象,并非Some类的实例,因此无法调用原型上的hi方法。
下面是几种可以克隆对象树且保留原型链的方案:
1. 手动实现递归克隆函数
这个方法会完整保留原型链,同时递归处理嵌套对象,支持所有自有属性(包括不可枚举属性和Symbol属性):
class Some { hi() { return 'hi' } } function deepCloneWithPrototype(obj) { // 处理null和基本数据类型 if (obj === null || typeof obj !== 'object') return obj; // 创建与原对象原型一致的新对象 const clonedObj = Object.create(Object.getPrototypeOf(obj)); // 获取原对象所有自有属性的描述符 const propertyDescriptors = Object.getOwnPropertyDescriptors(obj); // 遍历所有自有属性(包括Symbol) for (const key of Reflect.ownKeys(obj)) { const descriptor = propertyDescriptors[key]; // 如果属性值是对象,递归克隆 if (typeof descriptor.value === 'object' && descriptor.value !== null) { descriptor.value = deepCloneWithPrototype(descriptor.value); } // 将属性描述符赋值给克隆对象 Object.defineProperty(clonedObj, key, descriptor); } return clonedObj; } // 测试 const a = new Some(); console.log(a.hi()); // 输出: hi const b = deepCloneWithPrototype(a); console.log(b.hi()); // 输出: hi console.log(b instanceof Some); // 输出: true
2. 在自定义类中实现clone方法
如果是你自己定义的类,可以直接在类内部实现克隆逻辑,更灵活地控制克隆过程:
class Some { hi() { return 'hi' } clone() { // 创建当前类的新实例 const cloned = new this.constructor(); // 复制自有属性(浅克隆,如需深克隆需递归处理嵌套对象) const ownProps = Object.getOwnPropertyDescriptors(this); Object.defineProperties(cloned, ownProps); // 针对嵌套对象的深克隆处理示例 for (const key of Object.keys(ownProps)) { const value = this[key]; if (typeof value === 'object' && value !== null && !(value instanceof Date)) { cloned[key] = deepCloneWithPrototype(value); } } return cloned; } } // 测试 const a = new Some(); const b = a.clone(); console.log(b.hi()); // 输出: hi console.log(b instanceof Some); // 输出: true
3. 使用第三方库(可选)
如果项目中已经引入了第三方工具库,比如lodash,它的cloneDeep方法默认会保留对象的原型链:
const b = _.cloneDeep(a); console.log(b.hi()); // 输出: hi console.log(b instanceof Some); // 输出: true
内容的提问来源于stack exchange,提问作者Alex Craft
相关产品推荐
相关产品推荐

