5.理解浅拷贝与深拷贝?

1. 浅拷贝与深拷贝

1.1 浅拷贝

  • 浅拷贝中,简单数据类型是值传递。
  • 引用数据类型,传递的是地址,修改拷贝对象中的对象元素属性,原对象中对象属性也会被修改。

1.2 深拷贝

深拷贝传递的是对象,并在堆中为其分配一个新的内存空间,修改拷贝对象的属性不会影响到原对象。

2. 拷贝方法

2.1 浅拷贝方法

2.1.1 拷贝对象

  • 方法:
// 1. 对象扩展运算符{...obj} 
{...sources}
// 2.Object.assign()
Object.assign(target, sources)
  • 例:
<script>
    let obj = {
        uname: '美杜莎',
        age: 18,
        sex: '女',
        body: {
            uname: '七彩吞天蟒',
            age: 17
        }
    }
    console.log('obj=', obj)

    // 1. 使用对象扩展运算符进行浅拷贝 {...对象名}      
    let p1 = { ...obj }
    console.log('p1=', p1) // {uname:'美杜莎',age: 18,sex: '女',body:{...}}

    // 2. 使用对象方法 assign() 进行浅拷贝
    let p2 = Object.assign({}, obj)
    console.log('p2=', p2) // {uname:'美杜莎',age: 18,sex: '女',body:{...}}

    // 3. 浅拷贝中:引用数据类型,传递的是地址,修改拷贝对象中的对象元素属性,原对象中对象属性也会被修改。
    let p3 = { ...obj }
    p3.body.age = 12
    console.log('p3=', p3)
    console.log('obj=', obj)
</script>

由图可见,修改拷贝对象中的嵌套对象元素值,原对象中的值也被改变了。
在这里插入图片描述

2.1.2 拷贝数组

使用以下数组方法返回的都是一个新的数组,不会改变原来的数组。

  • 方法:
// 1. Array.prototype.slice() 截取
arr.slice()
// 2.  Array.prototype.concat() 结合
arr.concat()
// 3. [...arr]
[...arr]
  • 例:
<script>
    let arr = [1, 2, 3, 4, 5, 6, 7]
    console.log('arr=', arr) // arr= (7) [1, 2, 3, 4, 5, 6, 7]

    // 1.使用Array.slice() 截取方法
    // slice(start) start代表索引号,当只有一个参数时,表示从这个索引号开始,一直截取到最后
    let arr1 = arr.slice()
    let arr2 = arr.slice(3)
    console.log('arr1=', arr1) // arr1= (7) [1, 2, 3, 4, 5, 6, 7]
    console.log('arr2=', arr2) // arr2= (4) [4, 5, 6, 7]

    // slice(start,end) 从start位置开始,截取到end位置,end位置上的值保留
    let arr3 = arr.slice(3, 6)
    let arr4 = arr.slice(9, 3) // start不可大于end,否则截取不成功
    console.log('arr3=', arr3) // arr3= (3) [4, 5, 6]
    console.log('arr4=', arr4) // arr4= []

    // 2. 使用Array.concat() 合并方法
    let arr5 = arr.concat()
    console.log('arr5=', arr5) // arr5= (7) [1, 2, 3, 4, 5, 6, 7]

    // 3. 使用扩展运算符
    let arr6 = [...arr]
    console.log('arr6=', arr6) // arr6= (7) [1, 2, 3, 4, 5, 6, 7]
</script>

2.2 深拷贝方法

  • 深拷贝的好处就是新对象和旧对象互不影响。
  • 实现深拷贝的方法有如下:

2.2.1 递归实现

  • 简单数据直接使用遍历进行值传递
  • 需要判断复杂数据类型为数组还是对象(一定要先处理数组中的数据,再处理对象中的数据)
  • 复杂数据类型则需要再调用递归函数进行再遍历,直到其中的数据为简单类型为止。
<!-- 
   一、具体实现思路:
    1.若旧对象中属性为简单数据类型,直接遍历进行值传递 
    1.若旧对象中属性为数组类型,需要为新数组初始化一个空的相同属性的数组,再调用递归函数进行判断,直到最深一层为简单数据类型,直接进行值传递;
    2.若旧对象中属性为对象类型,需要为新数组初始化一个空的相同属性的对象,再调用递归函数进行判断,直到最深一层为简单数据类型,直接进行值传递;
        
    二、注意事项:
    1.先判断数组,再判断对象 因为:console.log(Array instanceof Object) 结果为 true
    2.当遍历对象为数组类型,key为索引号;若为对象,key为属性名
    3.key为变量,所以需要使用[]动态为新数组添加属性
 -->
<script>
    const obj = {
        uname: '美杜莎',
        age: 18,
        state: ['七彩吞天蟒', '美杜莎'],
        vertion1: {
            uname: '七彩吞天蟒',
            level: '魔兽之尊'
        }
    }
    console.log('obj=', obj)

    // 定义拷贝函数 反复对复杂数据类型的再遍历 直到最深一层为简单数据类型
    function Copy(targetObj, sourcesObj) {
        for (let key in sourcesObj) {
            // 1. 处理数组数据
            if (sourcesObj[key] instanceof Array) {
                // 初始化 targetObj[key]也为数组
                targetObj[key] = []
                // 调用递归函数, 遍历直到为简单数据为止
                Copy(targetObj[key], sourcesObj[key])
            }

            // 2. 处理对象数据
            else if (sourcesObj[key] instanceof Object) {
                // 初始化 targetObj[key]也为数组
                targetObj[key] = {}
                // 调用递归函数, 遍历直到为简单数据为止
                Copy(targetObj[key], sourcesObj[key])
            }
            else {
                // 简单数据类型值传递
                // targetObj[uname]=sourcesObj[uname] 
                targetObj[key] = sourcesObj[key]
            }
        }
    }

    const p1 = {}

    // 调用拷贝函数
    Copy(p1, obj)
    // console.log('p1=', p1) 和obj一样
    p1.age = 20
    p1.state[0] = '小七'
    p1.vertion1.level = '斗圣'
    console.log('p1=', p1)
</script>

2.2.2 lodash 实现

  • Lodash 是一个一致性、模块化、高性能的 JS的一个库。利用里面的cloneDeep可实现深拷贝。
  • 使用:下包 -> 导包 -> 语法
  • 语法:
 targetObj=_.cloneDeep(sourcesObj)

点击查看官方说明使用方法

2.2.3 JSON实现

<script>
    const obj = {
        uname: '美杜莎',
        age: 18,
        state: ['七彩吞天蟒', '美杜莎'],
        vertion1: {
            uname: '七彩吞天蟒',
            level: '魔兽之尊'
        }
    }
    console.log('obj=', obj)

    /*  
    // 将对象转换成字符串,以值的方式存储在栈空间中
     let p1 = JSON.stringify(obj)
     // 将字符串转换成一个新的对象,重新开辟空间存储,与原对象互不影响
     let p2 = JSON.parse(p1)
     console.log('p1=',p1)
     console.log('p2=',p2) */

    const p1 = JSON.parse(JSON.stringify(obj))
    p1.vertion1.level = '斗圣'
    console.log('p1=', p1)
</script>

3. 总结

  • 浅拷贝传递的是地址,原对象与新对象之间会相互影响;深拷贝传递的是对象,不会相互影响。
  • 浅拷贝方法有:对象扩展运算符、Object.assign()、Array.slice() 截取、Array.concat() 合并;深拷贝方法有:递归、Lodash中的cloneDeep方法和JSON转化。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值