JavaScript实现深拷贝

深拷贝

思路:递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
有种特殊情况需注意就是对象存在循环引用的情况,即对象的属性直接的引用了自身的情况,解决循环引用问题,我们可以额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系,当需要拷贝当前对象时,先去存储空间中找,有没有拷贝过这个对象,如果有的话直接返回,如果没有的话继续拷贝,这样就巧妙化解的循环引用的问题。

function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);

  // 排除掉非数组和对象类型,函数类型也是直接返回即可
  if (typeof obj !== "object") return obj;

  // 处理循环引用问题,如果已经存在,则将存在的返回
  if (hash.get(obj)) return hash.get(obj);

  // 简单来说 new xxx.constructor 可以拿到obj的类型
  // 复杂来说 使用了原对象的构造方法,所以它可以保留对象原型上的数据,如果直接使用普通的{},那么原型必然是丢失了的。
  let cloneObj = new obj.constructor();

  hash.set(obj, cloneObj);
  // 拿到待拷贝对象的key,进行递归拷贝
  for (let key in obj) {
    // for in 循环同样在查找对象属性时遍历原型链上的所有属性,
    // 使用 hasOwnProperty 方法, 这将会避免原型对象扩展带来的干扰
    // hasOwnProperty 可以用来排除原型链上的属性
    // if (obj.hasOwnProperty(key)) {
    //   cloneObj[key] = deepClone(obj[key], hash);
    // }

    // 又或是使用其他方法循环来
    const isArray = Array.isArray(obj)
    const keys = isArray? obj : Object.keys(obj) 
    let i = 0;
    while(i <= keys.length-1) {
      cloneObj[keys[i]] = deepClone(obj[keys[i]], hash);
      i++;
    }

    // 对象
  }

  return cloneObj;

}
// 原型上的方法并不喜欢被拷贝下来
Object.prototype.bar = {a:'test'}
let obj = { name: 1, address: { x: 100 } };
obj.o = obj; // 对象存在循环引用的情况
let d = deepClone(obj);
obj.address.x = 200;

console.log(d);
function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  if (typeof obj !== "object") return obj;
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();

  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}
Object.prototype.bar = {a:'test'}
let obj = { name: 1, address: { x: 100 } };
obj.o = obj;
let d = deepClone(obj);
obj.address.x = 200;
console.log(d);

声明

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值