javascript克隆对象深度介绍


在JavaScript中,克隆对象可以分为浅拷贝(shallow copy)和深拷贝(deep copy)两种方式。这两种方式在处理对象时有着本质的区别,尤其是在处理对象中包含对象(嵌套对象)时。

### 浅拷贝(Shallow Copy)

浅拷贝会创建一个新对象,这个新对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型(比如对象或数组),拷贝的就是内存地址,因此如果属性值是一个对象,那么浅拷贝后两个对象会共享这个对象的引用。

#### 实现方式

- **Object.assign()**


  const original = { a: 1, b: { c: 2 } };
  const copy = Object.assign({}, original);
  copy.b.c = 3; // 原始对象也会受到影响
  console.log(original.b.c); // 输出: 3
  

- **展开运算符(Spread Operator)**


  const original = { a: 1, b: { c: 2 } };
  const copy = { ...original };
  copy.b.c = 3; // 原始对象也会受到影响
  console.log(original.b.c); // 输出: 3
  

### 深拷贝(Deep Copy)

深拷贝会递归拷贝一个对象,创建一个全新的对象,并拷贝原对象及其子对象中的每一层属性到新的对象中。深拷贝后的对象与原对象是完全隔离的,修改新对象不会影响原对象。

#### 实现方式

- **JSON.parse() 和 JSON.stringify()**

注意:这种方法有局限性,如无法处理函数、undefined、symbol等特殊值,且会忽略对象的原型链。


  const original = { a: 1, b: { c: 2 } };
  const copy = JSON.parse(JSON.stringify(original));
  copy.b.c = 3;
  console.log(original.b.c); // 输出: 2
  

- **递归函数**

对于更复杂的对象或需要处理函数等特殊值的情况,可以使用递归函数来实现深拷贝。


  function deepCopy(obj, hash = new WeakMap()) {
    if (obj === null) return null; // null 的情况
    if (obj instanceof Date) return new Date(obj); // 日期对象直接返回一个新的日期对象
    if (obj instanceof RegExp) return new RegExp(obj); // 正则对象直接返回一个新的正则对象
    // 如果循环引用了就用 weakmap 来解决
    if (hash.has(obj)) return hash.get(obj);

    let allDesc = Object.getOwnPropertyDescriptors(obj);
    let clone = Object.create(Object.getPrototypeOf(obj), allDesc);
    hash.set(obj, clone);

    for (let key of Reflect.ownKeys(obj)) {
      clone[key] = (typeof obj[key] === 'object' && obj[key] !== null)
        ? deepCopy(obj[key], hash)
        : obj[key];
    }
    return clone;
  }
  
  const original = { a: 1, b: { c: 2 } };
  const copy = deepCopy(original);
  copy.b.c = 3;
  console.log(original.b.c); // 输出: 2
  

深拷贝和浅拷贝的选择取决于具体的应用场景。在需要完全隔离原始数据的情况下,深拷贝是更好的选择。