• 数组和对象的浅拷贝和深拷贝


    前言: 对于拷贝需要考虑数据的类型

      数据类型分为:基本数据类型和引用类型;

      基本数据类型是存储在栈中的简单数据;常见:String,Number,Undefined,Null,Boolean以及Es6新定义的Symbol;

      引用类型值是引用类型实例,它是保存在堆中的一个对象,引用类型是一中数据结构;常见:Array,Object,Function,Date,RegExp等,Es6提供的set和map新的数据结构;

      复制时的区别:

        基本数据类型是按值访问的;

        引用类型复制时,是复制的存在栈中的指针,指针指向堆内的数据,如果只是简单的赋值,就只是赋值了栈中的指针,通过一个变量操作堆内的对象会影响两者;

    一、浅拷贝

      理解:创建一个新对象,这个对象有这原始对象属性值的一份精确拷贝;如果是基本类型,则拷贝的是基本类型的值,如果是引用类型,则拷贝的是内存地址,所以一个对象改变了这个地址对应点堆内数据,则会影响到另外一个对象

      1:Object.assign(target,...source)

        # ES6提供的浅拷贝的方法,接受的第一个参数是拷贝的目标,第二个参数将要拷贝的源对象

        # Object.assign()只是拷贝根属性上的值(对象的第一层属性),如果根属性上的值是引用类型的数据,则仍是浅拷贝

        # 特点: 不会拷贝继承的属性;可以拷贝symbol类型的值;

        # 可以理解为:Object.assign()只是简单的=赋值,遍历从右到左遍历source上的属性赋值到target目标对象上

      2:扩展运算符 - 浅拷贝

        var cloneObj = { ...obj } // 对象

        var cloneArr = [ ...arr ]  // 数组

        # 对于值是对象的属性无法完全拷贝成两个完全不相同的对象;但是如果对象的值都是基本数据类型的话,扩展运算符还是比较方便的

      3:Array.property.slice() - arr.slice(begin, end)

        返回一个新的数组对象,这一对象是由begin和end决定的原数组的浅拷贝;原数组不改变;

      4:concat():该方法是连接两个或多个数组,但它不会修改原先的数组;问题:只会对第一层进行拷贝,对深层的不起作用

    二、深拷贝

      理解:将一个对象在内存中完整的拷贝出来,并内存中开辟一个新的空间存放新对象,这两个对象是相互独立的,且修改新对象不会影响原先的对象

      1:JSON.stringify()   JSON.parse()

      原理:将对象序列化成JSON字符串,将对象的内容转化成字符串的形式再保存到磁盘上,再用JSON.parse()反序列化将JSON字符串转换成新的对象

      注意:拷贝的对象的值有函数、undefined、symbol则经过反序列化后的JSON字符串中的键值对会消失;对象中包括NaN、infinity则序列化的后变为null

    // JSON
    var obj = {
        name: 'zs',
        arr : [ '1', 'a', { msg: '打贝贝' }]
    }
    // 针对对象深拷贝
    var newObj = {}
    // 便利对象里的键进行JSON编码和解析
    for (var k in obj) {
        newObj = JSON.parse(JSON.stringfiy(obj[k]))
    }
    // 该方法对对象里的值是基本数据类型是可以的,对于引用类型是不成立的

      2:递归

    // 2:递归深拷贝
    var obj   =   { 
           name: "贝贝",     
           age: 20,     
           arr: [ '1', 'a', { msg: '揍贝贝!' },     
           obj: {
             console.log('内层的对象')
           }  
    }
    
    function deepClone(obj) {
        // 判断obj是数组还是对象,响应的格式进行拷贝
        const cloneObj = Array.isArray(obj) ? [] : {}
        // 拷贝对象不能为空且是对象
        if (obj && typeOf obj === 'Object')  {
            for (var k in obj) {
            // 判断对象里是否有键
          if (obj.hasOwnProperty(k)) {      
                if (obj[k]&& typeOf obj[k] === 'Object') {
                    cloneObj[k] = deepClone(obj)
                } else {
                    cloneObj[k] = obj[k]
                }
           }
            }
        }
        return cloneObj
    }     
    // 该方法只是针对object引用类型的值进行循环迭代

       3:lodash和jquery都有已经封装好的深拷贝的方法,有兴趣的可以深入研究下

  • 相关阅读:
    android:screenOrientation属性详解
    Android APP混淆后,友盟分享功能出错的解决办法
    Android 混淆出错各种解决办法
    转一个工作三年的Android开发人员的思考
    Android 工程混淆后无法找到自定义控件类的解决方案
    Android Studio无法启动的解决方案 cannot start or open
    niz键盘windows键失效的解决办法:恢复出厂设置
    决策树学习资料
    人工智能行业发展趋势
    转:深度聚类算法研究综述(A Survey of Deep Clustering Algorithms)
  • 原文地址:https://www.cnblogs.com/xsk-walter/p/13207773.html
Copyright © 2020-2023  润新知