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 ] }
    ```







  • 相关阅读:
    C单链表操作
    如何为linux系统设置全局的默认网络代理
    Linux下动态库使用小结
    图片替代鼠标光标
    axios+FormData文件上传
    vue之回车触发表单提交
    viewer 照片查看器
    contains 之 点击元素外位置隐藏元素
    vue-cli 3.0之跨域请求代理配置及axios路径配置
    css之单边阴影
  • 原文地址:https://www.cnblogs.com/hqkbk/p/13720260.html
Copyright © 2011-2022 走看看