十分钟学会 前端面试题 js 深拷贝与浅拷贝

我们从以下三个方面进行学习浅拷贝和深拷贝

1.首先了解为什么要学习浅拷贝和深拷贝?

2.浅拷贝的概念和用法,以及优缺点。

3.深拷贝的概念和用法,深拷贝的好处。

下面我们开始学习啦!

以下代码中 console.log() 后面注释皆为控制台输出结果。

第一部分:对象赋值问题(学习深浅拷贝的原因)

开发中我们经常需要复制一个对象。如果直接用赋值会有下面问题:

如下面的代码:将对象p1赋值给p2,改变p2里面属性的值,p1里面对应的值也会被改变。

改变原因:因为赋值的时候,是直接拷贝对象栈里面的地址,p1和p2的地址相同,所以修改会将两个一起改变。

<script>
        // 创建一个p1对象
        const p1 = {
            name: '小白',
            age: 18
        }

        const p2 = p1
        console.log(p2); //{ name: '小白',age: 18}

        p2.name = '小黑'
        console.log(p2); //{name: '小黑', age: 18}
        console.log(p1); //{name: '小黑', age: 18}
    </script>

那么,如果我们只想改变p2里面的,p1不变,我们该怎么避免这种情况呢?

第二部分浅拷贝

浅拷贝: 将一个对象的所有属性拷贝到另一个对象  (并且改变拷贝的对象, 不影响原始对象)

学习浅拷贝 --- 两个方法     

(1)Object.assign()       

(2) ... 展开运算符

 浅拷贝 核心是 ---  创建新地址

(1)Object.assign() 方法

         语法:Object.assign(拷贝的对象,原始对象)

<script>
        // 创建一个p1对象
        const p1 = {
            name: '小白',
            age: 18
        }

        const p2 = {}
        Object.assign(p2, p1)
        console.log(p2); //{ name: '小白',age: 18}

        p2.name = '小黑'
        console.log(p2); //{name: '小黑', age: 18}
        console.log(p1); //{ name: '小白',age: 18}
    </script>

(2) ... 展开运算符方法

         语法:{...原始对象}

 <script>
        // 创建一个p1对象
        const p1 = {
            name: '小白',
            age: 18
        }

        const p2 = {...p1}
        console.log(p2); //{ name: '小白',age: 18}

        p2.name = '小黑'
        console.log(p2); //{name: '小黑', age: 18}
        console.log(p1); //{ name: '小白',age: 18}
    </script>

浅拷贝的问题: 当原始对象里面的属性值复杂数据类型的时候, 浅拷贝就会有bug,浅拷贝没有对这个值创建新地址

简单来说就是浅拷贝: 只能拷贝一层对象,或者一层数组

bug的来源就是:如果原始对象有嵌套对象的时候,那么他还是采用等号赋值, 地址依然一样,在堆里面值只有一份

 <script>
        // 创建一个p1对象
        const p1 = {
            name: '小白',
            age: 18,
            address: {
                province: '北京',
                citys: '东城区'
            }

        }

        const p2 = {}
        Object.assign(p2, p1)
        console.log(p2); //{ name: '小白',age: 18,address: {province: '上海', citys: '东城区'}}

        p2.name = '小黑'
        p2.address.province = '上海'
        console.log(p2); //{name: '小黑', age: 18,address: {province: '上海', citys: '东城区'}}
        console.log(p1); //{ name: '小白',age: 18,address: {province: '上海', citys: '东城区'}}
    </script>

第三部分深拷贝

深拷贝: 将一个对象的所有属性拷贝到另一个对象  (并且改变拷贝的对象, 也不影响含多层对象的原始对象)

学习深拷贝 --- 三个方法     

(1)通过递归实现深拷贝       

(2)  JSON.stringify()   JSON.parse()

(3) lodash

 深拷贝 核心是 ---  创建新地址

(1)通过递归实现深拷贝     

 拓展: 函数递归: 如果一个函数在内部可以调用其本身,那么这个函数就是递归函数

        简单理解:函数内部自己调用自己, 这个函数就是递归函数

        递归函数的作用和循环效果类似 由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件 return

<script>
        let num = 1

        function fn() {
            num++
            console.log(num);

            //退出条件
            if (num > 5) {
                return
            }
            fn()
        }

        fn()
    </script>

递归实现深拷贝:代码如下

<script>
        // 1.创建初始对象
        const p1 = {
            name: '小白',
            age: 18,
            address: {
                province: '北京',
                citys: '东城区'
            }

        }

        // 2.递归函数
        function deepClone(old) {
            const p2 = {}

            for (let key in old) {
                if (typeof old[key] === 'object') {
                    p2[key] = deepClone(old[key])
                } else {
                    p2[key] = old[key]
                }

            }
            return p2
        }

        const p2 = deepClone(p1)
        console.log(p2); //{ name: '小白',age: 18,address: {province: '上海', citys: '东城区'}}

        // 3.改变拷贝对象里面的 多层对象的值,原始的对象里面的值就不会被改变了
        p2.address.province = '上海'
        console.log(p2); //{ name: '小白',age: 18,address: {province: '上海', citys: '东城区'}}
        console.log(p1); //{ name: '小白',age: 18,address: {province: '北京', citys: '东城区'}}
    </script>

(2)  JSON.stringify()   JSON.parse()方法   (工作中使用)           

 JSON.stringify()   将对象转换为字符串   JSON字符串

 JSON.parse()       转换为复杂数据类型

为什么可以这样写:因为关键就是创建新地址,字符串是普通数据类型,地址在栈里面

                                JSON.stringify()转换成字符串就是一个新地址  

 <script>
        // 1.创建初始对象
        const p1 = {
            name: '小白',
            age: 18,
            address: {
                province: '北京',
                citys: '东城区'
            }

        }

        // 转换
        const p2 = JSON.parse(JSON.stringify(p1))
        console.log(p2); //{ name: '小白',age: 18,address: {province: '上海', citys: '东城区'}}

        // 3.改变拷贝对象里面的 多层对象的值,原始的对象里面的值就不会被改变了
        p2.address.province = '上海'
        console.log(p2); //{ name: '小白',age: 18,address: {province: '上海', citys: '东城区'}}
        console.log(p1); //{ name: '小白',age: 18,address: {province: '北京', citys: '东城区'}}
    </script>

深拷贝的缺陷:

     

 

(3) lodash                  

  利用js库 lodash里面的  _.cloneDeep()

  lodash工具库:https://www.lodashjs.com/  

 <script src="./lodash.min.js"></script>
    <script>
        // 1.创建初始对象
        const p1 = {
            name: '小白',
            age: 18,
            address: {
                province: '北京',
                citys: '东城区'
            }

        }

        // 转换
        const p2 = _.cloneDeep(p1) //深拷贝
        console.log(p2); //{ name: '小白',age: 18,address: {province: '上海', citys: '东城区'}}

        // 3.改变拷贝对象里面的 多层对象的值,原始的对象里面的值就不会被改变了
        p2.address.province = '上海'
        console.log(p2); //{ name: '小白',age: 18,address: {province: '上海', citys: '东城区'}}
        console.log(p1); //{ name: '小白',age: 18,address: {province: '北京', citys: '东城区'}}
    </script>

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值