• Object对象的浅拷贝与深拷贝方法详解


    /* ===================== 直接看代码 ===================== */
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8">
      <title></title>
    </head>
    <body>
      <h1>http://www.codeceo.com/article/javascript-object-deep-copy.html</h1>
      <p>
        对象的深拷贝与浅拷贝的区别如下:
        浅拷贝:仅仅复制对象的引用,而不是对象本身;
        深拷贝:把复制的对象所引用的全部对象都复制一遍。
      </p>
      一. 浅拷贝的实现
    <script type="text/javascript">
      Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象 (简单粗暴明了 推荐首选
      详情直戳 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
      function test() {
        'use strict';
    
        let obj1 = { a: 0 , b: { c: 0}};
        let obj2 = Object.assign({}, obj1);
        console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
      
        obj1.a = 1;
        console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
        console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
      
        obj2.a = 2;
        console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
        console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
      
        obj2.b.c = 3;
        console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
        console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
      
        // Deep Clone 
        obj1 = { a: 0 , b: { c: 0}};
        let obj3 = JSON.parse(JSON.stringify(obj1));
        obj1.a = 4;
        obj1.b.c = 4;
        console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}
    
        // 拷贝单个对象 
        var obj = { a: 1 };
        var copy = Object.assign({}, obj);
        console.log(copy); // { a: 1 }  
    
        // 合并多个对象
        let o1 = { a: 1 };
        let o2 = { b: 2 };
        let o3 = { c: 3 };
    
        let obj = Object.assign(o1, o2, o3);
        console.log(obj); // { a: 1, b: 2, c: 3 }
        console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变
      }
    
      // 需要注意的是浅拷贝的话当自身或者目标对象改变两者皆会改变  (希望不改变则需要深拷贝)
      test();
    
    
    </script>
    <script type="text/javascript">
      二. 深拷贝的实现
      要实现深拷贝有很多办法,有最简单的 JSON.parse() 方法,也有常用的递归拷贝方法,和ES5中的 Object.create() 方法。
      
    2.1 方法一:使用 JSON.parse() 方法   要实现深拷贝有很多办法,比如最简单的办法是使用 JSON.parse()   function deepClone(initalObj) {   var obj = {};   try {    obj = JSON.parse(JSON.stringify(initalObj));   }    return obj;   }   var obj = {   a: {   a: "world",   b: 21   }   }   var cloneObj = deepClone(obj);   cloneObj.a.a = "changed";   console.log(obj.a.a); // "world"   这种方法简单易用。   但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。   这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。
      2.2 方法二:递归拷贝   为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。   版代码如下:
     // 深拷贝 递归1.1 写法一
      function deepClone(obj) {
          var obj = {};
          for (var i in initalObj) {
              var prop = initalObj[i];
              // 避免相互引用对象导致死循环,
              if(prop === obj) {
                  continue;
              }
              if (typeof prop === 'object') {
                  obj[i] = (prop.constructor === Array) ? [] : {};
                  arguments.callee(prop, obj[i]);
              } else {
                  obj[i] = prop;
              }
          }
          return obj;
      }
     
    // 深拷贝 递归1.2 写法二
    function deepCopy(p, c) {
      var c = c || {};
      for (var i in p) {
        if (typeof p[i] === 'object') {
          c[i] = (p[i].constructor === Array) ? [] : {};
          deepCopy(p[i], c[i]);
        } else {
           c[i] = p[i];
        }
      }
      return c;
    }


      
     // 深拷贝 递归1.3 写法二  比较全面的写法 参考至 (https://mp.weixin.qq.com/s/vXbFsG59L1Ba0DMcZeU2Bg
      function forEach(array, cloneTarget) {
        let index = -1;
        const length = array.length;
        while (++index < length) {
          cloneTarget(array[index], index);
        }
        return array;
      }
    
      function clone(target, map = new WeakMap()) {
        if (typeof target === 'object') {
          const isArray = Array.isArray(target);
          let cloneTarget = isArray ? [] : {};
          if (map.get(target)) {
            return target;
          }
          map.set(target, cloneTarget);
          const keys = isArray ? undefined : Object.keys(target);
          forEach(keys || target, (value, key) => {
            if (keys) key = value
            cloneTarget[key] = clone(target[key], map);
          });
          return cloneTarget;
        } else {
          return target;
        }
      }
      2.3 方法三:集合Object.assign()方法
      // 深拷贝
      function deepClone(initalObj) {
          var obj = {};
          for (var i in initalObj) {
              var prop = initalObj[i];
              // 避免相互引用对象导致死循环
              if(prop === obj) {
                  continue;
              }
              if (typeof prop === 'object') {
                  obj[i] = Object.assign(prop);
              } else {
                  obj[i] = prop;
              }
          }
          return obj;
      }
    </script>
    </body>
    </html>

    有问题或者有bug非常欢迎留言指正。

    深拷贝1.3版本参考至: https://mp.weixin.qq.com/s/vXbFsG59L1Ba0DMcZeU2Bg  (递归方法总结的很全面推荐)

  • 相关阅读:
    第二次会议
    第五次团队会议
    作业六:团队项目——编写项目的Spec
    DFD数据流程图
    第四次会议
    精通 VC++ 实效编程280例 03 控制栏
    1.窗体与界面设计工具栏设计
    HTML5开发 Local Storage 本地存储
    1.窗体与界面设计菜单应用实例
    精通 VC++ 实效编程280例 02 菜单和光标
  • 原文地址:https://www.cnblogs.com/ljx20180807/p/9790239.html
Copyright © 2020-2023  润新知