zoukankan      html  css  js  c++  java
  • 深拷贝与浅拷贝详解

     
    #### 拷贝有个大前提,是针对对象的操作,当想复制一个对象的时候,才存在浅拷贝深拷贝之分!!
    1. 浅拷贝的实现方式
       1. Object.assign()
          > 可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
       2. lodash的clone方法
       3. ...操作符
          ```javascript
          let obj1 = { name: 'Kobe', address:{x:100,y:100}}
          let obj2= {... obj1}
          obj1.address.x = 200;
          obj1.name = 'wade'
          console.log('obj2',obj2) // obj2 { name: 'Kobe', address: { x: 200, y: 100 } }
          ```
       4. Array.prototype.concat
          > let arr = [1,2,3]; let arr2 = [4,5,6];let arr3 = arr.concat(arr2)
          ```javascript
          let arr = [1, 3, {
              username: 'kobe'
              }];
          let arr2 = arr.concat();    
          arr2[2].username = 'wade';
          console.log(arr);
          ```
       5. Array.prototype.slice
          ```javascript
          let arr = [1, 3, {
              username: ' kobe'
              }];
          let arr3 = arr.slice();
          arr3[2].username = 'wade'
          console.log(arr); // [ 1, 3, { username: 'wade' } ]
          ```
    2. 深拷贝的实现方式
       1. JSON.parse(JSON.stringify())
          > 可以处理数组和对象的深拷贝,但是不能处理函数和正则,因为这两者基于这两个函数处理后得到的结果不再是正则/函数
          缺点:
            1. 会忽略undefined
            2. 会忽略symbol
            3. 不能序列化函数
            4. 不能解决循环引用的对象
       2. lodash的cloneDeep函数
       3. jQuery.extend函数
       4. 如果所拷贝的对象含有内置对象,但是不包含函数,可以使用`messagechannel`,可以拷贝undefined和循环引用的对象
          ```javascript
          function structuralClone(obj) {
            return new Promise(resolve => {
              const { port1, port2 } = new MessageChannel()
              port2.onmessage = ev => resolve(ev.data)
              port1.postMessage(obj)
            })
          }
          
          var obj = {
            a: 1,
            b: {
              c: 2
            }
          }
          
          obj.b.d = obj.b
          
          // 注意该方法是异步的
          // 可以处理 undefined 和循环引用对象
          const test = async () => {
            const clone = await structuralClone(obj)
            console.log(clone)
          }
          test()
          ```
          
    3. 手写浅拷贝:**遍历=>直接等号赋值**
    ```javascript
    // 浅拷贝
    let obj1 = {
        name : '深深地',
        arr : [1,[2,3],4],
    };
    let obj3=shallowClone(obj1)
    obj3.name = "春娇";
    obj3.arr[1] = [5,6,7] ; // 新旧对象还是共享同一块内存
    // 这是个浅拷贝的方法
    function shallowClone(source) {
        var target = {};
        for(var i in source) {
            if (source.hasOwnProperty(i)) {
                target[i] = source[i];
            }
        }
        return target;
    }
    console.log('obj1',obj1) // obj1 { name: '深深地', arr: [ 1, [ 5, 6, 7 ], 4 ] }
    console.log('obj3',obj3) // obj3 { name: '春娇', arr: [ 1, [ 5, 6, 7 ], 4 ] }
    ```
    > obj.hasOwnProperty,返回值是一个布尔值,即是否是obj的属性(原型上的是false)
    4. 深拷贝:**遍历,如果是简单数据类型直接赋值,如果是复杂数据类型递归。**
    ```javascript
    // 深拷贝
    let obj1 = {
        name : '春娇',
        arr : [1,[2,3],4],
    };
    let obj4=deepClone(obj1)
    obj4.name = "志明";
    obj4.arr[1] = [5,6,7] ; // 新对象跟原对象不共享内存
    // 这是个深拷贝的方法
    function deepClone(obj) {
        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;
        let cloneObj = new obj.constructor();
        for (let key in obj) {
          if (obj.hasOwnProperty(key)) {
            // 实现一个递归拷贝
            cloneObj[key] = deepClone(obj[key]);
          }
        }
        return cloneObj;
    }
    console.log('obj1',obj1) // obj1 { name: '春娇', arr: [ 1, [ 2, 3 ], 4 ] }
    console.log('obj4',obj4) // obj4 { name: '志明', arr: [ 1, [ 5, 6, 7 ], 4 ] }
    ```







  • 相关阅读:
    LeetCode 32. 最长有效括号(Longest Valid Parentheses)
    LeetCode 141. 环形链表(Linked List Cycle)
    LeetCode 160. 相交链表(Intersection of Two Linked Lists)
    LeetCode 112. 路径总和(Path Sum)
    LeetCode 124. 二叉树中的最大路径和(Binary Tree Maximum Path Sum)
    LightGBM新特性总结
    sql service 事务与锁
    C#泛型实例详解
    C# 中的委托和事件(详解)
    C# DateTime日期格式化
  • 原文地址:https://www.cnblogs.com/hqkbk/p/13720260.html
Copyright © 2011-2022 走看看