深拷贝和浅拷贝

1.深拷贝和浅拷贝的含义

深拷贝和浅拷贝是比较常遇到的问题,但是何为深拷贝?何为浅拷贝呢?
在讲两种拷贝之前我们首先还是需要了解一下javascript中数据的存储方式。

1.1基本数据类型 和 引用数据类型

javascript有7种数据类型,但是总的可以划分为两大类,一类是基本数据类型,一类是引用数据类型
对于 基本数据类型基本数据类型是存放在栈内存中,当我们对栈中的基本数据类型进行拷贝的时候,栈内存会开辟一个新的内存来存放我们拷贝产生的变量;即如图,当栈里面已经存储了一个变量a,并且a=1,我们进行b=a的操作之后,就会出现如图的情况。所以这就是两个内存块上的东西,我们对b进行重新赋值也并不会影响到a;
在这里插入图片描述

//代码实现
let a = 1;
let b = a;
b = 2;
console.log(a);//输出 1
console.log(b);//输出 2

对于 引用数据类型引用数据类型同样的也会在栈内存中进行存储,但是它在栈内存中存储的不是数据,而是存储了一个指向该数据的指针,真实的数据是存放在堆内存中的。
就像下图所示一样,栈内存存放了指向“#20”这块地址的指针,在堆内存的“#20”地址中就存放了该数组的数据。
在这里插入图片描述
那么现在如果我们对数组进行复制,使用语句 arr1 = arr ,这样其实复制的就是一个指针,所以复制产生的 arr1 同样也会指向 “#20” 的地址。
在这里插入图片描述
所以当 arr 中的数据发生改变的时候,arr1中的数据也会发生改变,因为它们本质上是同一个数据

//代码实现
let arr = [1,2,3,4];
let arr1 = arr;
arr[0]=5;
console.log(arr);//[ 5, 2, 3, 4 ]
console.log(arr1);//[ 5, 2, 3, 4 ]
1.2 何为深拷贝?何为浅拷贝?

有了前面的铺垫,我们对两种数据的存储有了基本的认识。
接下来就是深浅拷贝的理解了。
举个例子,我们在定义一个对象 的时候,就会出现下面的这种情况。


let obj = {
  a:10,//基本数据类型
  b:20,//基本数据类型
  c:{//引用数据类型
    item:"c内部"
  }
}

浅拷贝就是我们会对这些属性进行一次拷贝,遇到基本数据类型就会把它的值拷贝过来,遇到引用数据类型就会把它的地址拷贝下来,这样原对象的引用数据新类型部分和新对象的引用数据类型部分就会有重叠,造成新对象修改自己本身的引用类型内部数据的时候,原对象的引用类型内部数据也会发生改变,而基本数据类型则不存在这个问题。
深拷贝就是指对不管对基本数据类型还是引用数据类型,都开辟一份对应的新的内存来存放他们,相当于对对象内部的对象进行一次浅拷贝,具体进行多少次浅拷贝就取决于该对象内部嵌套了多少层对象。

2.实现深拷贝和浅拷贝的方式
2.1 实现浅拷贝的方式–Object.assign()

实现浅拷贝最常用的是 Object.assign()

const obj = {
  name:"fjj",
  age:21,
  sex:"男",
  b:{
    item:55
  }
}
let obj1 = Object.assign({},obj);
obj1.name="lll";
obj1.age=30;
obj1.b.item = 77;
console.log(obj);//{ name: 'fjj', age: 21, sex: '男', b: { item: 77 } }
console.log(obj1);//{ name: 'lll', age: 30, sex: '男', b: { item: 77 } }
//通过代码我们可以发现,新对象对基本数据类型的修改不会影响原对象的基本数据类型,但是对于引用数据的修改则会影响。
2.2 实现深拷贝的方式–JSON.parse(JSON.stringify())
const obj = {
  name:"fjj",
  age:21,
  sex:"男",
  b:{
    item:55
  }
}
let obj2 = JSON.parse(JSON.stringify(obj));
obj2.name="lll";
obj2.age = 30;
obj2.b.item = 666;
console.log(obj);//{ name: 'fjj', age: 21, sex: '男', b: { item: 55 } }
console.log(obj2);//{ name: 'lll', age: 30, sex: '男', b: { item: 666 } }
//此时对引用类型的修改就不会相互影响,因为他们已经是存放放在不同内存中的两份数据了。
3.简单的实现一下浅拷贝和深拷贝
3.1实现浅拷贝函数
//浅拷贝的实现
function _assign(source){
  let dist = {};
  for(let key in source){
    if(source.hasOwnProperty){
      dist[key] = source[key];
    }
  }
  return dist;
}
let obj = {
  a:10,
  b:20,
  c:{
    item:"c内部"
  }
}
let _obj =_assign(obj);
_obj.a=30;
_obj.b=40;
_obj.c.item="c内部更改";
console.log(obj);//{ a: 10, b: 20, c: { item: 'c内部更改' } }
console.log(_obj);//{ a: 30, b: 40, c: { item: 'c内部更改' } }
3.2实现深拷贝函数
function deepClone(source){
  if(typeof source !== 'object') return source;
  let dist = source instanceof Array ? [] : {};
  for(let item in source){
    if(source.hasOwnProperty){
      dist[item] = typeof source[item] == 'object' ? deepClone(source[item]) : source[item];
      //如果访问到了对象类型,就进行递归调用,相当于对内部的对象数据再次进行一次浅拷贝,即深拷贝就相当于浅拷贝中再加浅拷贝
    }

  }
  return dist;
}

let obj = {
  a:10,
  b:20,
  c:{
    item:"c内部"
  }
}
let deepObj =deepClone(obj);
deepObj.a=30;
deepObj.b=40;
deepObj.c.item="c内部更改";
console.log(obj);//{ a: 10, b: 20, c: { item: 'c内部' } }
console.log(deepObj);//{ a: 30, b: 40, c: { item: 'c内部更改' } }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值