JavaScript中的手写深拷贝

完整版:

function deepCopy(obj, cache = new WeakMap()) {
  // 支持值类型
  // 与值类型相对的是对象类型,对象是指内存中的可以被标识符引用的一块区域
  if (!obj instanceof Object) return obj;
  // 防止循环引用
  if (cache.get(obj)) return cache.get(obj);
  // 支持函数
  if (obj instanceof Function) {
    return function () {
      return obj.apply(this, arguments);
    };
  }
  // 支持日期
  if (obj instanceof Date) return new Date(obj);
  // 支持正则
  if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
  // 支持Map
  if (obj instanceof Map) {
    const result = new Map();
    cache.set(obj, result);
    obj.forEach((val, key) => {
      // 注意:map中的值为object的话也得深拷贝
      if (val instanceof Object) {
        result.set(key, deepCopy(val, cache));
      } else {
        result.set(key, val);
      }
    });
    return result;
  }
  // 支持Set
  if (obj instanceof Set) {
    const result = new Set();
    cache.set(obj, result);
    obj.forEach((val) => {
      // 注意:set中的值为object的话也得深拷贝
      if (val instanceof Object) {
        result.add(deepCopy(val, cache));
      } else {
        result.add(val);
      }
    });
    return result;
  }
  // 数组是 key 为数字索引的特殊对象
  const res = Array.isArray(obj) ? [] : {};
  // 缓存 copy 的对象,用于处理循环引用的情况
  cache.set(obj, res);
  Object.keys(obj).forEach((key) => {
    if (obj[key] instanceof Object) {
      res[key] = deepCopy(obj[key], cache);
    } else {
      res[key] = obj[key];
    }
  });
  return res;
}

// 测试
const source = {
  name: "Jack",
  meta: {
    age: 12,
    birth: new Date("1997-10-10"),
    ary: [1, 2, { a: 1 }],
    say() {
      console.log("Hello");
    },
  },
};
source.source = source;
const newObj = deepCopy(source);
console.log("newObj: ", newObj);
console.log(newObj.meta.ary[2] === source.meta.ary[2]); // false
console.log(newObj.meta.birth === source.meta.birth); // false
console.log(
  "new Map(): ",
  new Map([
    ["number", "数字"],
    ["string", "字符串"],
    [{ obj: "对象" }, "对象作为键"],
  ])
);
console.log("new Set(): ", new Set([1, 2, 3, 1, "2"]));

 

简单版:

function deepCopy(obj) {
  let newObj = Array.isArray(obj)?[]:{};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof obj[key] === "object") {
        newObj[key] = deepCopy(obj[key]);
      } else {
        newObj[key] = obj[key];
      }
    }
  }
  return newObj
}

let obj_02 = deepCopy(obj_01);

 

posted @ 2021-02-14 17:31  starlog  阅读(136)  评论(0编辑  收藏  举报