js浅拷贝和深拷贝

深拷贝和浅拷贝问题的来由

这个问题归根到底还得从js的数据存出方式说起,js大体上分为两种数据类型,简单数据类型和复杂数据类型。简单数据类型因为其大小固定,故存储在栈内存中,可以直接访问;而复杂数据类型大小可变,故存储在堆内存中,然后再在栈内存当中存储一个指向堆内存的那块存储区域的地址,当我们要访问这个复杂数据类型的时候,我们就根据栈内存的地址找到堆内存中的它访问,即通过栈内存中的指针间接访问。

总结一下上面这段话:
1、简单数据类型:大小固定,存储在栈中,可以直接访问,包括number、string、Boolean 、undefined、null;
2、复杂数据类型:大小不定,存储在堆内存中,栈内存存储一个指向堆内存的地址,需间接访问,包括Object 、Array 、Date 、function;

存储方式的不同致使产生深、浅拷贝

浅拷贝:

function easyCopy(obj) {
      var cpObj = {}
      for (var key in obj) {
        cpObj[key] = obj[key]
      }
      return cpObj
    }
    var obj_1 = {
      name: '叶问',
      sex: 'man',
      hobby: ['咏春', '怕老婆'], // 复杂数据类型
    }
    var obj_2 = easyCopy(obj_1)
    console.log(obj_2)

控制台的结果:
在这里插入图片描述
此时obj_2成功的从obj_1拷贝过来了
接下来,我要开始操作了,我将修改obj_2的hobby属性
代码:

function easyCopy(obj) {
      var cpObj = {}
      for (var key in obj) {
        cpObj[key] = obj[key]
      }
      return cpObj
    }
    var obj_1 = {
      name: '叶问',
      sex: 'man',
      hobby: ['咏春', '怕老婆'], 		// 复杂数据类型
    }
    var obj_2 = easyCopy(obj_1)
    // console.log(obj_2)
    obj_2['hobby'].push('打架')      // 此处修改obj_2
    console.log(obj_1)					//打印obj_1

结果:
在这里插入图片描述
此时,有人可能会有疑问了,我明明修改的是obj_2,关obj_1什么事呢,但是结果就是obj_1的hobby数组多了一个元素: “打架”。真是见鬼了…

下面,将由我为大家解答

首先,我们分析一下obj_1对象的组成,有name、sex、hobby。
name、sex:字符串,基本数据类型,存储在栈内存当中;
hobby:数组,复杂数据类型,存储在堆内存当中,栈内存当中存储一个指向堆内存的指针;

其实,说白了,我们复制的obj_2,它的name、sex复制的是栈内存当中的值,因为栈内存当中的值可以直接访问,所以复制的就是name:“叶问”,sex:“man”;而hobby是复杂数据类型,栈内存当中仅仅存储一个地址,所以,复制的obj_2的bobby属性其实是一个地址,指向的是obj_1的hobby在堆内存当中的那块存储区域,所以,你改obj_2的hobby属性值,其实就是在改obj_1的hobby指向的堆内存存储区域里面的内容,换句话说,obj_1和obj_2的hobby属性都是地址,指向同一个堆内存区域。所以,你改obj_2的hobby,其实就是在改obj_1的hobby。结果就是,obj_1的hobby数组多了一个元素“打架”。

深拷贝

当然,浅拷贝在很多种情况下跟我们的意愿是相违背的,我们不想要类似这样的结果,obj_1和obj_2关联,我们希望我改obj_2的属性不影响obj_1,那我们就需要用到深拷贝了。
深拷贝主要思想就是利用递归(自己调用自己)实现。
代码:

var obj_1 = {
      name: '叶问',
      sex: 'man',
      hobby: ['咏春', '怕老婆'], // 复杂数据类型
    }
    function deepCopy(q, m) {
      var m = m || {}
      for (var i in q) {
        if (typeof q[i] === 'object') {
          m[i] = (q[i].constructor === Array) ? [] : {}	//此处用对象的构造函数判断其类型
          deepCopy(q[i], m[i]) //此处在自己调用自己
        } else {
          m[i] = q[i]
        }
      }
      return m
    }
    var obj_3 = deepCopy(obj_1)
    obj_3['hobby'].push('打架')
    console.log(obj_1)
    console.log(obj_3)

结果:
在这里插入图片描述
此时,我通过深拷贝deepCopy函数的到obj_3,我向obj_3的hobby数组添加了"打架"这个元素,打印obj_1的结果表明:obj_1的hobby数组并没有添加"打架"这个元素,最终得到结论:修改obj_3的bobby属性,不会影响obj_1的hobby属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值