一、采用JSON字符串实现深拷贝

  1. let obj = {
  2. name:'zhangsan',
  3. age:13,
  4. hobby:['basketball','pingpang','dance'],
  5. score:{
  6. a:1,
  7. b:2
  8. }
  9. }
  10. // 使用JSON进行深拷贝
  11. let res = JSON.parse( JSON.stringify(obj))
  12. // 测试代码
  13. res.score.a = 12
  14. console.log(res,obj)

缺点:

  1. 对象方法不会拷贝
  2. 数组中的undefined会变为null,对象上的undefined不会拷贝
  3. symbol不会拷贝
  4. 正则变成了空对象
  5. Infinite会变为null
  6. 一些类型的对象会被转换为字符串

    1. let obj = {
    2. c:new Date()
    3. }
    4. // 使用JSON进行深拷贝
    5. let res = JSON.parse( JSON.stringify(obj))
    6. console.log(res,obj)
    7. // res: c: '2022-02-23T03:15:43.266Z'
    8. // obj: c: Wed Feb 23 2022 11:15:43 GMT+0800 (中国标准时间)
  7. 循环引用会报错

    1. obj.score = obj
    2. // 使用JSON进行深拷贝
    3. let res = JSON.parse( JSON.stringify(obj))

    image.png

  8. 不能转换BigInt类型

image.png

二、递归实现

封装一个函数,解决json字符串深拷贝产生的问题 处理循环调用问题,可以使用:数组或set保存已经处理过的数据,解决循环引用的问题(本案例使用数组)

  1. // 封装一个获取数据类型的函数
  2. function toType(data) {
  3. return Object.prototype.toString.call(data).slice(8, -1)
  4. }
  5. // 使用递归方式处理深拷贝 ,参数1:要拷贝的数据,参数2:解决循环引用(不用传参)
  6. const deepClone = function (target, done = []) {
  7. // 处理一些特殊数据类型
  8. if (target == null) return target // 如果是null或undefined,如果是就返回该值
  9. // 获取数据的类型,以及其构造器(避免后面频繁用到)
  10. let type = toType(target)
  11. let col = target.constructor
  12. if (type === "RegExp" || type === "date") return new col(target) // 如果是正则或date返回新的实例
  13. if (type === "Error") return new col(target.message) // 如果是ERROR实例,返回该信息的实例
  14. if (type === 'Function') return function () { // 如果是函数,返回一个新的函数包裹该函数
  15. target.apply(this, arguments)
  16. }
  17. if (type !== "Array" && type !== "Object") return target // 不是对象和数组(除以上的其他基本数据类型),则返回该数据
  18. // 解决循环引用问题
  19. if (done.includes(target)) return target // 如果已经处理过该数据,就直接返回该数据(不处理)
  20. done.push(target) // 没有处理过的数据就放入该数组中,在递归时将done做为第二个参数传入
  21. // 数组或者对象,遍历递归
  22. let res = new col() // 创建一个新的数组或对象,用于存储拷贝后的数据
  23. Object.keys(target).forEach(key => { // 遍历对象或者数组
  24. res[key] = deepClone(target[key], done) //递归,第二个参数处理循环引用问题
  25. })
  26. return res
  27. }