第七篇 手写原理代码 - 对象 【 实现对象的深度拷贝、实现对象的深度对比 】

发布时间 2023-04-11 23:20:11作者: caix-1987
在 JavaScript 中,对象拷贝可以分为浅拷贝和深拷贝两种方式

1、浅拷贝

  浅拷贝只是复制了对象的引用地址,新对象的属性与原对象的属性指向同一块内存地址
  
2、深拷贝

  深拷贝会完整地复制对象以及其内部所有嵌套对象  
  
使用 JSON.parse(JSON.stringify()) 方法进行深拷贝时,需要注意以下几点:

 1、对象属性值只能是基本数据类型、数组或对象字面量,不能包含方法、正则表达式等特殊类型
 
 2、对象中存在循环引用时会报错

1、实现对象的深度拷贝

function deepClone(obj, hash = new WeakMap()) {
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  if (typeof obj !== 'object' || obj === null) return obj;
  if (hash.has(obj)) return hash.get(obj);

  const clone = new obj.constructor();
  hash.set(obj, clone);
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {  // 处理自有属性
      clone[key] = deepClone(obj[key], hash);  // 如果是对象,则递归复制
    }
  }
  
  return clone;
}

2、实现对象的深度对比

以下方法仅考虑了对象的可枚举属性,如果对象还包含不可枚举属性(例如通过 Object.defineProperty 方法定义的属性),则需要使用 Object.getOwnPropertyNames() 方法来获取所有属性名称,从而实现完整的深度对比。

function deepEqual(a, b) {
  if (a === b) return true;

  if (a instanceof Date && b instanceof Date) {
    return a.getTime() === b.getTime();
  }
  
  if (a instanceof RegExp && b instanceof RegExp) {
    return a.toString() === b.toString();
  }

  if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) {
    return false;
  }

  const propsA = Object.getOwnPropertyNames(a);
  const propsB = Object.getOwnPropertyNames(b);

  if (propsA.length !== propsB.length) {
    return false;
  }

  for (let i = 0; i < propsA.length; i++) {
    const prop = propsA[i];

    const isEqual = deepEqual(a[prop], b[prop]);

    if (!isEqual) {
      return false;
    }
  }

  return true;
}