什么是深拷贝?浅拷贝?它们有什么区别?看完,你就全懂了!!!

1. 什么是浅拷贝与深拷贝?
         如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝;  如果B没变,那就是深拷贝!

例子:

let a=[0,1,2,3,4],
    b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);


嗯?明明b复制了a,为啥修改数组a,数组b也跟着变了 ? 继续看下面!

那么这里,就得引入 基本数据类型 与 引用数据类型 的概念了。

3. 基本数据类型和引用数据类型
        面试也会经常问:基本数据类型有哪些? number,string,boolean,null,undefined五类。

引用数据类型(Object类)有常规名值对的无序 对象 {a:1},数组[1,2,3],以及函数等。

而这两类数据存储分别是这样的:

a.基本类型–键值存储在栈内存中

当你b=a复制时,栈内存会新开辟一个内存,例如这样:

所以当你此时修改a=2,对b并不会造成影响,因为此时的b已自食其力,翅膀硬了,不受a的影响了。当然,let a=1,b=a;虽然b不受a影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。

b.引用数据类型–键存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,我们以上面浅拷贝的例子画个图:

当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。

当我们 **a[0]=1 **时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。


那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了


这里就抛出本篇文章的核心问题:如何实现对引用数据类型进行拷贝时希望它开辟新的堆空间,而非引用原地址的堆空间。及所谓的深拷贝。

5. 深拷贝,是拷贝对象各个层级的属性(占坑)

例:

let a=[1,2,3,4];
let b=a.slice();
a[0]=2;
console.log(a,b);


那是不是说 slice 方法也是深拷贝了,毕竟b也没受a的影响,上面说了,深拷贝是会拷贝所有层级的属性,还是这个例子,我们把a 再改改(添加了一个双层数组)

let a=[0,1,[2,3],4];
let b=a.slice();
a[0]=1;
a[2][0]=1;
console.log(a,b);


拷贝的不彻底啊,b对象的一级属性确实不受影响了,但是二级属性还是没能拷贝成功,仍然脱离不了a的控制,说明slice根本不是真正的深拷贝。

这里引用知乎问答里面的一张图


第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题。

同理,concat 方法与 slice 也存在这样的情况,他们都不是真正的深拷贝,而是属于浅拷贝,他们其实是披着羊(qian)皮(kao)的(bei)狼。这里需要注意。

那如何实现真正的深拷贝?

JS 中深拷贝的几种实现方法

1、使用递归的方式实现深拷贝

//使用递归的方式实现数组、对象的深拷贝
function deepClone1(obj) {
  //判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
  var objClone = Array.isArray(obj) ? [] : {};
  //进行深拷贝的不能为空,并且是对象或者是
  if (obj && typeof obj === "object") {
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (obj[key] && typeof obj[key] === "object") {
          objClone[key] = deepClone1(obj[key]);
        } else {
          objClone[key] = obj[key];
        }
      }
    }
  }
  return objClone;
}

2、通过 JSON 对象实现深拷贝

//通过js的内置对象JSON来进行数组对象的深拷贝
function deepClone2(obj) {
  var _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
  return objClone;
}

JSON对象实现深拷贝的一些问题 
* 无法实现对对象中方法的深拷贝

3、通过jQuery的extend方法实现深拷贝

var array = [1,2,3,4];
var newArray = $.extend(true,[],array);

4、Object.assign()拷贝

       当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

5、lodash函数库实现深拷贝

         lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
深拷贝是指对一个对象进行递归拷贝,拷贝了对象的所有层次,包括父对象和子对象。换句话说,深拷贝会创建一个新的对象,与原对象完独立,对拷贝对象的修改不会影响原对象。\[3\] 浅拷贝是对一个对象的顶层拷贝,只拷贝了父对象,而不会拷贝对象内部的子对象。换句话说,浅拷贝只是创建了一个新的引用,指向原对象的内存地址,对拷贝对象的修改会反映到原对象上。\[1\] 举个例子,假设有一个列表a = \[1, 2, 3, 4, \['a', 'b'\]\],使用赋值操作b = a,这是对象的引用,对b的修改会影响到a。使用浅拷贝c = copy.copy(a),只拷贝了a的顶层,对c的修改会反映到a上。而使用深拷贝d = copy.deepcopy(a),会递归地拷贝a的所有层次,对d的修改不会影响到a。\[2\] #### 引用[.reference_title] - *1* [深拷贝浅拷贝](https://blog.csdn.net/YanLingGe/article/details/121865921)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [浅拷贝深拷贝区别](https://blog.csdn.net/m0_73770538/article/details/126898545)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [深拷贝(deepcopy)与浅拷贝(copy)的区别](https://blog.csdn.net/peng78585/article/details/125574564)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值