什么是深拷贝,和浅拷贝有什么区别,动手实现一个深拷贝

什么是深拷贝,和浅拷贝有什么区别,动手实现一个深拷贝
最新回答
甜心少女

2026-07-30 14:33:56

深拷贝是指创建一个新对象,并递归复制原对象的所有属性,包括嵌套对象和引用类型的属性,确保新对象与原对象完全独立,修改新对象不会影响原对象。

浅拷贝则只复制对象的第一层属性,若属性值为引用类型(如对象、数组),则复制的是引用地址而非实际值,导致新旧对象共享同一引用,修改会影响原对象。

深拷贝与浅拷贝的核心区别
  1. 复制深度

    浅拷贝:仅复制第一层属性,嵌套引用类型仍共享。

    深拷贝:递归复制所有层级,完全独立。

  2. 影响范围

    浅拷贝:修改嵌套引用类型会影响原对象。

    深拷贝:任何修改均不影响原对象。

深拷贝的实现代码解析

以下是一个完整的深拷贝函数实现,处理了多种数据类型(如Date、RegExp、Symbol等):

function cloneDeep(obj) { // 处理基本类型和null if (obj === null || typeof obj !== 'object') return obj; // 处理特殊对象类型 if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (obj instanceof Map) return new Map(Array.from(obj, ([key, val]) => [key, cloneDeep(val)])); if (obj instanceof Set) return new Set(Array.from(obj, val => cloneDeep(val))); // 处理Symbol属性 if (typeof obj === 'symbol') return Symbol(obj.description); // 创建新对象(保留原型链) const cloneObj = new obj.constructor(); // 处理对象属性(包括Symbol属性) const allKeys = Reflect.ownKeys(obj); // 获取所有属性键(包括Symbol) for (const key of allKeys) { cloneObj[key] = cloneDeep(obj[key]); // 递归拷贝 } return cloneObj;}代码示例与对比测试对象let obj = { a: 100, b: [10, 20, 30], c: { x: 10 }, d: new Date(), f: undefined, g: /s+/g, fn: function() {}, symbol: Symbol('Symbol'), [Symbol('key')]: 'symbolValue'};拷贝结果对比
  1. JSON.parse(JSON.stringify(obj))

    缺点:无法处理Date、RegExp、undefined、函数、Symbol等。

    结果:

    { a: 100, b: [10, 20, 30], c: { x: 10 }, d: '2023-10-01T00:00:00.000Z', // Date转为字符串 g: {} // RegExp丢失}
  2. 自定义cloneDeep函数

    优点:完整保留所有数据类型和结构。

    结果:

    { a: 100, b: [10, 20, 30], c: { x: 10 }, d: Date对象, // 保留Date实例 f: undefined, g: /s+/g, // 保留RegExp fn: [Function: fn], symbol: Symbol(Symbol), [Symbol(key)]: 'symbolValue' // 包含Symbol属性}
关键点说明
  1. 递归处理:通过递归遍历所有属性,确保嵌套对象也被深拷贝。
  2. 特殊类型处理

    Date/RegExp:直接创建新实例。

    Map/Set:遍历并递归拷贝值。

    Symbol:通过Symbol(description)创建新Symbol。

  3. 原型链保留:使用new obj.constructor()确保新对象与原对象原型一致。
  4. Symbol属性:通过Reflect.ownKeys()获取所有属性键(包括Symbol)。
注意事项
  • 循环引用:上述代码未处理循环引用(如obj.self = obj),会导致栈溢出。可通过WeakMap记录已拷贝对象解决。
  • 性能:深拷贝递归调用可能影响性能,超大对象需谨慎使用。
完整解决方案(含循环引用处理)function cloneDeep(obj, hash = new WeakMap()) { if (obj === null || typeof obj !== 'object') return obj; // 处理循环引用 if (hash.has(obj)) return hash.get(obj); if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); if (obj instanceof Map) return new Map(Array.from(obj, ([key, val]) => [key, cloneDeep(val, hash)])); if (obj instanceof Set) return new Set(Array.from(obj, val => cloneDeep(val, hash))); const cloneObj = new obj.constructor(); hash.set(obj, cloneObj); // 记录已拷贝对象 const allKeys = Reflect.ownKeys(obj); for (const key of allKeys) { cloneObj[key] = cloneDeep(obj[key], hash); } return cloneObj;}

通过以上实现,可安全处理绝大多数数据类型的深拷贝需求。