对象的深浅拷贝

JS中基本类型是按值传递的,而对象不同,是按引用传值,所以对于像 Object。Array这样的复杂对象,存在深浅拷贝的问题。

从层次上来看,对象的复制可以简单地分为浅复制和深复制,顾名思义,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,对象的深复制会复制对象中层层嵌套的对象的属性。

从内存上来看,浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创建一个一模一样的对象,新对象跟原来的对象不共享内存,修改新对象不会改变原对象。

在复制对象时,除了要复制对象的属性外,还要兼顾到是否保留了对象的constructor属性,是否对每一种数据类型都能实现正确的复制。

浅拷贝的方法:

  1. 遍历属性拷贝
function shallowCopy(obj){
    let newObj = {};
    if(typeof obj !== 'object') return;
    newObj.constructor = obj.constructor
    for(let key of Object.keys(obj)){
        if(obj.hasOwnProperty(key)){
            newObj[key] = obj[key];
        }
    }
    return newObj
}

浅拷贝只会将对象的属性全部进行复制,并不会递归复制。
2. Object.create()和Object.assign()

function clone(origin) {
    let originProto = Object.getPrototypeOf(origin);
    return Object.assign(Object.create(originProto), origin)
}
let obj = { a: 1, b: { c: 3 }}
let obj2 = clone(obj)

obj2.b.c = 10
obj2.b.c === obj.b.c // true

上面两个方法都是ES6对象新增的,Object.assign()可以实现浅复制,Object.getPrototypeOf可以保存对象的原型链。

深拷贝的方法

  1. 递归拷贝
function deepCopy(obj){
    let newObj = {};
    if(typeof obj !== 'object') return;
    newObj.constructor = obj.constructor
    for(let key of Object.keys(obj)){
        if(obj.hasOwnProperty(key)){
            newObj[key] = typeof obj[key] === 'object'? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj
}

这个方法把对象的属性都遍历一遍,如果属性值是对象,还会递归调用去复制,并且保留了原始对象的constructor,是对深拷贝原理的完整实现,但是如果对象层次过深会存在性能问题。
2. Object.assign()

let obj = { a: 1, b: 2, c: 3 }}
let obj2 = Object.assign({}, obj)

Object.assign()方法实行的是浅拷贝,但是如果对象只有一层的话就可以利用它,先创建一个空对象{},然后把原对象的属性挨个复制过来,实现拷贝,这样修改新对象也不会影响到原对象。
3. 转成JSON再转回来

let obj = { a: 1, b: 2, c: 3}
let obj2 = JSON.parse(JSON.stringify(obj)

用JSON.stringify()把对象转成字符串,再用JSON.parse()把字符串转成新的对象,这样可以很简单的实现深拷贝,但是也存在无法复制函数和原型链丢失的缺点
4. loadash
函数库loadash有提供_.cloneDeep来做深拷贝

let obj = { a: 1, b: { c: 3 }}
let obj2 = _.cloneDeep(obj)

obj2.b.c = 10
obj2.b.c !== obj.b.c // true

总结:需要注意的是,如果对象比较大,层级也比较多,深复制会带来性能上的问题。在遇到需要采用深复制的场景时,可以考虑有没有其他替代方案,在实际的引用场景中,也是浅复制更为常用。

以上来自网络资料的总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值