深拷贝函数封装

深拷贝

前提

  • 基本数据类型有:number,string,boolean,null,undefined,symbol,BigInt;
  • 引用数据类型:object,array,function等;
  • 基本数据类型存储在栈内存中,当复制时,栈内存会新开辟一个内存,即对于基本类型的数据,是拷贝值,不会拷贝引用;
  • 对于引用类型的数据,它们的名字存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,当复制时,其实复制的是引用地址,而非堆里面的值,所以我们要在堆内存中也开辟一个新的内存存放拷贝值,(调用他们的构造函数,创建一个新的引用,之后遍历原引用类型中的所有属性,递归拷贝);
  • 在写之前先定义一个引用数据类型,以下的测试都可以用这个数据
const obj = {
  name:'张三',
  info: {
    age: 20,
    sex: 'male',
    fancy:['唱歌','跳舞']
  }
}

JSON 方法

  • 不支持值为undefined、函数和循环引用的情况;
const cloneObj = JSON.parse(JSON.stringify(obj))

递归法拷贝

  • 第一种
function deepCopy(obj, cache = new WeakMap()) {
  if(obj === null || typeof obj !== 'object') return obj
  if(obj instanceof Date) return new Date(obj)
  if(obj instanceof RegExp) return new RegExp(obj)
  if(cache.has(obj)) return cache.get(obj)
  let newObj = new obj.constructor()
  //缓存对象,记录已经拷贝过的引用类型属性,值为拷贝后的新的引用,在发现循环引用之后,直接使用缓存中的结果,而不是再次拷贝,避免循环引用的情况
  cache.set(obj, newObj)
  for(let key in obj) {
  //hasOwnProperty() 方法是 Object 的原型方法(也称实例方法),它定义在 Object.prototype 对象之上,所有 Object 的实例对象都会继承 hasOwnProperty() 方法;是用来检测属性是否为对象的自有属性,如果是,返回true,否者false;
  //hasOwnProperty() 只会检查对象的自有属性,对象原形上的属性其不会检测;但是对于原型对象本身来说,这些原型上的属性又是原型对象的自有属性,所以原形对象也可以使用hasOwnProperty()检测自己的自有属性;
    if(obj.hasOwnProperty(key)) {
      newObj[key] = deepCopy(obj[key], cache)
    }
  }
  return newObj
}
  • 第二种
function deepCopy(obj) {
  if(obj === null || typeof obj !== 'object') return obj
  if(Object.prototype.toString.call(obj) === "[Object Date]") return new Date(obj)
  if(Object.prototype.toString.call(obj) === "[Object RegExp]") return new RegExp(obj)
  if(Object.prototype.toString.call(obj) === "[Object Undefined]") return new Error(obj)
  let newObj = Array.isArray(obj) ? [] : {}
  //for-in只是获取数组的索引;而for-of会获取数组的值;
  //for-in会遍历对象的整个原型链,性能差;而for-of只遍历当前对象,不会遍历原型链;
  //对于数组的遍历,for-in会返回数组中所有可枚举的属性(包括原型链上可枚举的属性);for-of只返回数组的下标对应的属性值;
  //for-of适用遍历数组/字符串/map/set等有迭代器对象的集合,但是不能遍历普通对象(obj is not iterable).
  for(let key in obj) {
    if(typeof obj[key] === 'object'){
      newObj[key] = deepCopy(obj[key])
    }else{
      newObj[key] = obj[key]
    }
  }
  return newObj
}
  • 第三种
function deepCopy(obj) {
  if(obj === null || typeof obj !== 'object') return obj
  let cache = null
  if(!deepCopy.cache) deepCopy.cache = new WeakMap()
  cache = deepCopy.cache
  if(cache.has(obj)) return cache.get(obj)
  //Set 和 Map 类型的数据,我们需要拿出来它们其中所有的数据,再递归的拷贝,因为如果这里的数据有引用类型的,使用 Set、Map 构造函数,并传递原数据,仍然是浅拷贝;
  if(obj instanceof Set) {
    const temp = new Set()
    cache.set(obj, temp)
    obj.forEach(item => {
      temp.add(deepCopy(item))
    })
    return temp
  }else if(obj instanceof Map) {
    const temp = new Map()
    cache.set(obj, temp)
    obj.forEach(item => {
      temp.set(key, deepCopy(item))
    })
    return temp
  }else if(obj instanceof RegExp) {
    return new RegExp(obj)
  }else if(obj instanceof Date) {
    return new Date(obj)
  }else{
    const temp = new obj.constructor()
    cache.set(obj, temp)
    for(let key in obj) {
      temp[key] = deepCopy(obj[key])
    }
    return temp
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值