JavaScript的深克隆

50 阅读1分钟

1:递归深拷贝

function deepClone1(obj) {
  const target = {};
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      if (typeof obj[key] === "object") {
        target[key] = deepClone1(obj[key]);
      } else {
        target[key] = obj[key];
      }
    }
  }
  return target;
}

2: JSON.parse JSON.stringify

缺点: 1:变量不能是方法 函数直接被忽略掉了 2:不能循环调用

function deepClone2(target) {
  if (typeof target === "object" && target !== null) {
    return JSON.parse(JSON.stringify(target));
  } else {
    return target;
  }
}

3 递归处理数组

function deepClone3(target) {
  if (typeof target === "object" && target !== null) {
    let result = Array.isArray(target) ? [] : {};
    if (Array.isArray(target)) {
      target.forEach((item, index) => {
        result[index] = deepClone4(item);
      });
    } else {
      Object.keys(target).forEach((key) => {
        result[key] = deepClone4(target[key]);
      });
    }
    return result;
  } else {
    return target;
  }
}

终极版本


function deepClone4(target) {
  // map解决循环引用的问题
  const map = new Map(); // 用map将已经访问过得对象存起来
  const clone = (obj) => {
    // 如果是已经访问过得对象,直接返回  避免循环引用导致栈溢出

    if (map.has(obj)) {
      return obj;
    }
    if (obj === null || typeof obj !== "object") return obj;
    if (obj instanceof Boolean) return new Boolean(obj.valueOf());
    if (obj instanceof `Number`) return new Number(obj.valueOf());
    if (obj instanceof String) return new String(obj.valueOf());
    if (obj instanceof RegExp) return new RegExp(obj.valueOf());
    if (obj instanceof Date) return new Date(obj.valueOf());
    let cpObj = obj instanceof Array ? [] : {};
    map.set(obj, 1);
    for (let key in obj) {
      cpObj[key] = clone(obj[key]);
    }
    return cpObj;
  };
  return clone(target);
}

测试用例



const temp = {};
const obj = {
  a: temp,
  b: undefined,
  c: new RegExp(/\w/),
  d: () => {
    console.log(123);
  },
};
temp.b = obj;
const finall = deepClone4(obj);
console.log(finall.d === obj.d);
finall.d();
console.log(finall);