深拷贝VS浅拷贝 ,合并对象

深拷贝

深拷贝是将一个对象从内存中完整的拷贝一份出来。从堆内存中开辟一个新的区域存放新的对象(新旧对象不共享同一块内存),且修改新对象不会影响到原来的对象。(深拷贝是在堆内存申请新的空间来存储数据,避免指针悬挂)(递归地复制对象及其所有嵌套子对象,生成完全独立的副本。 )

实现方式如下

JSON.parse(JSON.stringify())

注意: 上面的方法虽然可以实现数组或对象的深拷贝,但是不能处理函数和正则,,经过上面的拷贝后得到的正则就不再是正则(变为空对象),得到的函数也不再是函数(变为null)。

递归方法实现深度克隆:遍历对象、数组直到里面是基本数据类型,然后再去复制,就是深度拷贝。  

function  deepClone(obj) {
        if (typeof obj !== 'object' || obj == null) {
            return obj
        }
        let result
        if (obj instanceof Array) {
            result = []
        } else {
            result = {}
        }
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                result[key] = deepClone(obj[key])
            }
        }
        return result
    }


    function deepClone(obj, hash = new WeakMap()) {
        if (obj === null) return obj; //如果是null或者是undefined 我就不进行拷贝操作
        if (obj instanceof Date) return new Date(obj);
        if (obj instanceof RegExp) return new RegExp(obj);  //如果可能是对象或者普通的值如果是函数的话就不需要拷贝
        if (typeof obj !== "object") return obj   //是对象的话就要深拷贝
        if (hash.get(obj)) return hash.get(obj);
        let cloneObj = new obj.constructor();
        //找到的是所属类型上的constructor,而原型上的constructor指向的是当前的类本身
        hash.set(obj, cloneObj);
        hash.set(obj, cloneObj)
        for (let key in obj) {
            if (obj.hasOwnProperty('key')) {
                cloneObj[key] = deepClone(obj[key], hash)
            }
        }
        return cloneObj
    }
  1. 使用第三方库(其实也是和上面的方法一样)

例如 Lodash 提供了 _.cloneDeep() 方法,可以方便地进行深拷贝。

const _ = require('lodash');

const deepCopy = _.cloneDeep(original); 

浅拷贝

浅拷贝是创建一个新对象,这个对象有着原始对象的属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存的地址。所以其中一个对象改变了地址,就会影响到另一个对象。(仅复制对象的第一层属性,嵌套对象通过引用共享 )

实现方式如下

1、Object.assign(); 可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,最后返回目标对象。

 let obj1 = {
        person: {
            name: '张三',
            age: 21
        },
        sports: 'basketball'
    }
    let obj2 = Object.assign({}, obj1)
    obj2.person.name = "艺青桑";
    obj2.sports = "football";
    console.log(obj1) // {person: {name: '艺青桑', age:21},sports: "basketball"}
    console.log(obj2); //    {person: {name: '艺青桑', age:21}, sports: 'football'}
 

2、展开运算符 是es6的特性,它提供了一种非常方便的方式来进行浅拷贝,与object.assign()的功能相同

let obj1 = { name: '文博', address: { x: 100, y: 100 } }
    let obj2 = { ...obj1 };
    obj1.address.x = 200;
    obj1.name = '嘉兴';
    console.log(obj2);//{ name: '文博', address: { x: 200, y: 100 }}
    console.log(obj1);//{ name: '嘉兴', address: { x: 200, y: 100 }}

3、Array.prototype.concat();

 let arr=[1,3,{username:'贺丽'}]
    let arr2=arr.concat();
    arr[2].username='亚楠';
    console.log(arr)  //[1,3,{username:'亚楠'}]

4、 Array.prototype.slice()

let arr = [1, 3, { username: '再兴' }]
    let arr3 = arr.slice();
    arr3[2].username = '艺青';
    console.log(arr) // [1,3,{username:'艺青'}]

  赋值与深浅拷贝的区别

赋值深拷贝浅拷贝
当我们把一个对象赋值给一个新的变量时,赋的其实是给该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论那个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。
和原数据是否指向同一对象第一层数据为基本数据类型且修改基本类型数据时原数据中包含子对象且修改子对象时
赋值改变会使原数据一起改变改变会使原数据一起改变
深拷贝改变不会使原数据一起改变改变不会使原数据一起改变
浅拷贝改变不会使原数据一起改变改变会使原数据一起改变

合并对象的方法

1、object.assign()

2、扩展运算符

3 、封装方法

  function extend(target,source){
    for(var obj in  source){
        target[obj]=source[obj];
    }
    return target
   }

文章中提到的栈内存和堆内存,有不懂得可以参观下面的地址

秒懂 栈内存和堆内存(深入底层)-CSDN博客

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值