对象的深拷贝

1. ES5 来实现对象的深拷贝

在这里插入图片描述

  • 详细注释
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script type="text/javascript">
    var obj = {
      name: 'zhangbing',
      age: 10,
      info: {province: '湖北省', university: 'CUC', classNo: 3, hobbies: ['唱歌', '读书', '篮球', {a: 1}]}

    }

    // params:
    // 	 origin: 待拷贝的对象
    // 	 target : 拷贝后产生的新对象 
    function deepClone(origin, target) {
      var tar = target || {} // target 参数如果没传的话默认为空对象
      var toStr = Object.prototype.toString 
      var arrType = '[object Array]' // Object.prototype.toString([]) === '[object Array]'

      // 遍历待对象的每一项
      for (var k in origin) {
        // 首先判断属性是否位于对象本身上,不拷贝原型上的属性
        if (origin.hasOwnProperty(k)) {
          // 遍历的项如果为对象且不为null(因为 typeof null === ’object')
          if (typeof origin[k] === 'object' && origin[k] !== null) {
            // 遍历的项如果为数字总用【】来包裹其进一步拷贝的内容
            // 否则遍历的项为对象,则使用{}来包裹其进一步拷贝的内容
            tar[k] = toStr.call(origin[k]) === arrType ? [] : {}
            // 递归进行内层的深拷贝
            deepClone(origin[k], tar[k])
          } else {
            // 如果遍历项为值类型,直接赋值复制
            tar[k] = origin[k]
          }
        }
      }
      // 返回深拷贝得到的新对象
      return tar
    }

    // 测试深拷贝代码的效果

    const newObj = deepClone(obj, {})
    newObj.info.hobbies[3].a = 3
    console.log(obj)
    console.log(newObj)
  </script>
</body>
</html>
  • 控制台输出结果:

在这里插入图片描述

2. WeakMap 知识铺垫

在这里插入图片描述
WeakMap的引入可以解决当按钮节点被删除后,绑定的事件处理函数需要设置为null才能被垃圾回收机制清除掉的问题。 因为WeakMap 的键名是弱引用,将事件处理函数设置为键值可以弥补手动设置为null的问题,当节点移除后事件处理函数也会自动清除掉。

3. ES6的方法实现深拷贝(引入WeakMap)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script type="text/javascript">
    function deepClone(origin, hashMap = new WeakMap()) {
      // 当 origin 为null/undefined 或者为值类型时,直接返回origin
      if (origin == undefined || typeof origin !== 'object') {
        return origin
      }
      // 当 origin 为 Date 类型时, 返回Date类型的数据
      if (origin instanceof Date) {
        return new Date(origin)
      }
      // 当 origin 为 RegExp 类型时, 返回 RegExp 类型的数据
      if (origin instanceof RegExp) {
        return new RegExp(origin)
      }
      // 找到hashKey,看当前传进来的 origin 的 hashKey 是否存在
      const hashKey = hashMap.get(origin)
      // 存在就直接return
      if (hashKey) {
        return hashKey
      }
      // 当origin为数组时,target初始化为[]; 当origin为对象时,target初始化为{}
      const target = new origin.constructor() 

      hashMap.set(origin, target)

      for (let k in origin) {
        if (origin.hasOwnProperty(k)) {
          target[k] = deepClone(origin[k], hashMap)
        }
      }
      return target
    }

    // var obj = {
    //   name: 'zhangbing',
    //   age: 10,
    //   info: {province: '湖北省', university: 'CUC', classNo: 3, hobbies: ['唱歌', '读书', '篮球', {a: 1}]}
    // }

    // const newObj = deepClone(obj)
    // newObj.info.hobbies[3].a = 3
    // console.log(obj)
    // console.log(newObj)
    // 可以看到成功实现了深拷贝

    let test1 = {}
    let test2 = {}
    test2.test1 = test1 // 
    test1.test2 = test2
    console.log(deepClone(test2)) // Uncaught RangeError: Maximum call stack size exceeded
    // 可以看到存在循环引用的问题 ,程序会报错。
    // 这个问题想到使用Map来解决,也就是hash
  </script>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值