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

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

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

  基本数据类型是存储在栈中的简单数据;常见: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都有已经封装好的深拷贝的方法,有兴趣的可以深入研究下

原文地址:https://www.cnblogs.com/xsk-walter/p/13207773.html