深拷贝与浅拷贝

数据存储规则

数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型
对于基本数据类型来说,它声明的名字和值都存储在栈内存中。
例如 let a = 2
在这里插入图片描述

对于引用数据类型来说,栈内存存储的是变量名以及对象在堆内存中的存储地址,通过这个地址找到存储在堆内存的值。
在这里插入图片描述

深浅拷贝

对基本类型进行拷贝时,
let a = 2
let b = a
在这里插入图片描述
当你把 a 赋值给 b 时,会在栈内存中重新开辟一块空间来存放,所以即使你修改 a,b 的值也不会改变。

对引用数据类型进行拷贝时,
let a = [1,2,3]
let b = a
在这里插入图片描述
这里复制的其实是 a 的引用地址,而并非堆里面的值。当我们令 a[0] = 2 时,由于 a 与 b 都指向了同一个地址,那 b 也同时受到了影响。这就是所谓的浅拷贝。

所以简言之,如果 b 复制了 a ,如果改变了a的值,b的值也跟着改变的话,那就是浅拷贝,如果b 不受影响的话,就是深拷贝。(这里需要注意深拷贝本身只针对较为复杂的object类型数据,所以上面例子中基本类型的拷贝算不上是深拷贝)

现在我们就明白了如果能在堆内存中也开辟一个新的内存专门来存放b的值,就像基本类型那样,就达到了深拷贝的效果。
在这里插入图片描述

实现深拷贝的方法

可以通过 JSON.parse(JSON.stringify(object)) 来解决

let a = {
  age: 1,
  sex: {
    first: 'man'
  }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'woman'
console.log(b.jobs.first) // man

利用递归来实现深复制,对属性中所有引用类型的值遍历到是基本类型的值为止。

function deepClone(obj){    
  if(!obj && typeof obj !== 'object'){      
    throw new Error('error arguments', 'shallowClone');    
  }    
  var targetObj = Array.isArray(obj) ? [] : {};    
  for(var keys in obj){       
    if(obj.hasOwnProperty(keys)){ 
      //判断ojb子元素是否为对象,如果是,递归复制         
      if(obj[keys] && typeof obj[keys] === 'object'){  
        targetObj[keys] = deepClone(obj[keys]);    //递归      
      }else{            
        targetObj[keys] = obj[keys];         
      }       
    }    
  }    
  return targetObj; 
}

由于我们需要考虑好多种边界情况,比如原型链如何处理、DOM 如何处理等等,所以这里我们实现的深拷贝只是很基本的。

还有一种更为推荐的实现深拷贝的方式就是使用 lodash 的深拷贝函数。
详情见https://www.jianshu.com/p/35d69cf24f1f.

本文是自己学习时的一篇笔记整理,参考了以下文章:
lhttps://www.cnblogs.com/echolun/p/7889848.html.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值