深拷贝与浅拷贝的区别和理解

一般拷贝的使用场景主要是,将对象或者数组赋值到新的变量中。但是这样就会出现一个问题,当改变新的对象或数组时,源数组或对象也会发生改变,那么这个时候要根据实际情况使用深度拷贝,还是浅拷贝,这里不能一股脑的使用深度拷贝,毕竟深度拷贝对于性能的消耗还是蛮大的

对于像forEach、map、filter 如果操作的是基本数据类型则不会影响原始数据,一旦是对象、数组这种引用类型的,那么操作数据同样会影响原始数据

区别

浅拷贝: 将原对象或者原数组直接赋给新的变量,这里赋值的对象或者数据的引用,他们内存中指向的地址是一个,所以新变量的值进行改变,其原对象或者数组也会发生改变
深拷贝: 将原对象或者原数组的值赋给新的变量中,这里是赋值的值,而不是引用,那么当新变量的值发生改变,原对象或数组不会发生改变

使用

浅拷使用

循环遍历赋值

循环遍历数组进行赋值

let array = [1, 2, 3, 4]
let newArray = [];
array.forEach((item) => {
   newArray.push(item)
})
newArray[0] = 10
console.log("原数组==>>"+array)
console.log("新数组==>>"+newArray)

效果:
在这里插入图片描述
不是说是浅拷贝吗,改变新数组,原数组会改变吗,这里为什么并没有达到预期?
**原因:**虽然原数组是一个引用类型,但因为遍历数组赋值的是数值类型(基本类型),所以并不会产生同一个引用。所以才有上述的情况

直接进行赋值就会发生改变

let array = [1, 2, 3, 4]
let newArray = [];
newArray=array;
newArray[0] = 10
console.log("原数组==>>"+array)
console.log("新数组==>>"+newArray)

效果:
在这里插入图片描述
或者数组对象

        let array = [{
            num: 1
        }, {
            num: 2
        }, {
            num: 3
        }, {
            num: 4
        }]
        let newArray = [];
        array.forEach(i => {
            newArray.push(i)
        })
        newArray[0].num = 10
        console.log(`原数组==>>${JSON.stringify(array)}`)
        console.log(`新数组==>>${JSON.stringify(newArray)}`)

在这里插入图片描述
可以看到这里直接赋值,而因为产生同一个引用,所以产生了原数组改变的预期:

slice

slice() 方法可从已有的数组中返回选定的元素。返回一个新数组

        let array = [{
            num: 1
        }, {
            num: 2
        }, {
            num: 3
        }, {
            num: 4
        }]
        let newArray = array.slice();
        newArray[0].num = 10
        console.log(`原数组==>>${JSON.stringify(array)}`)
        console.log(`新数组==>>${JSON.stringify(newArray)}`)

效果:
在这里插入图片描述
可以看到数组对象情况下修改新数组,原数组会改变,该方法和第一种遍历的方法是同样的效果。其中如果数数组数值非引用类型,就不会改变原数组

concat

方法用于连接两个或多个数组。
该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

 	let array = [{
            num:1
        },{
            num:2
        },{
            num:3
        },{
            num:4
        }]
        let newArray = array.concat();
        newArray[0].num = 10
        console.log(`原数组==>>${JSON.stringify(array)}`)
        console.log(`新数组==>>${JSON.stringify(newArray)}`)

在这里插入图片描述
预期和上述是一致的

Object.assign

用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

 let obj={
            name:"浅拷贝"
        }
        let newObj=Object.assign({},obj);
        newObj.name="新拷贝"
        console.log(`原数组==>>${JSON.stringify(obj)}`)
        console.log(`新数组==>>${JSON.stringify(newObj)}`)

在这里插入图片描述
这里的数据其实和上面方法的数据有个共同点,1层结构,那么我改变新数组或对象的值不会对源数据产生影响
多层:

let obj={
            name:{
                nick:"nick"
            }
        }
        let newObj=Object.assign({},obj);
        newObj.name.nick="newNick"
        console.log(`原数组==>>${JSON.stringify(obj)}`)
        console.log(`新数组==>>${JSON.stringify(newObj)}`)

在这里插入图片描述
这里其他的方式就不做赘述了

深拷使用

JSON.parse(JSON.stringify())

使用json.stringify()转成一个字符串,然后再用json.parse()转成新的对象
但是这种方式只有可以转成Json对象的数据才可以使用,Function等无法转成Json对象的就不能使用

强大的lodash库

具体使用可以参考官方文档

深度递归

深度递归,递归每层,如果是引用类型那么就去继续递归,直到遇到是数值类型的,然后进行赋值,否则直接赋值

immutable

该库提供了众多的api,来实现深度拷贝
官网

总结

对于遍历、slice、concat、ES6扩展运算符(…)等等如果是拷贝的一层,那么其实改变新数组或对象是不会改变原数组或对象,那么这个时候对于只拷贝一层的可以在某种程度上称之为深拷贝,如果数组是数组对象,超过一层或者对象超过一层,这个时候就是浅拷贝。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值