js中的深克隆(深拷贝)和浅克隆(浅拷贝)

数据类型

我们都知道我们的数据类型分为两大类:

  1. 基本的数据类型有:number,string,boolean,null,undefined,symbol,
  2. 引用数据类型(Object)有:{},[] 和函数

数据类型的存储方式

  1. 基本数据类型
    基本类型–名值存储在栈内存中,例如let a=1;
    在这里插入图片描述
    当 b=a 进行赋值时,栈内存会开辟出一个新的内存存储 b
    在这里插入图片描述
    所以当你此时修改a=2,对b并不会造成影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的 object类型数据
  2. 引用数据类型
    引用数据类型–存在栈内存中,存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值
    例如:
let a=[0,1,2,3,4],
    b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);

在这里插入图片描述
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
在这里插入图片描述
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了
在这里插入图片描述

浅拷贝深拷贝描述

浅克隆:直接将存储在中的值赋值给对应变量,如果是基本数据类型,则直接赋值对应的值,如果是引用类型,则赋值的是地址

基本数据类型是直接存储在栈内存中的,而引用数据类型,则仅仅是把地址存储在栈内存中,真正的数据是存储在堆内存中的,赋值操作时,仅仅把地址进行了赋值。

深克隆:就是把数据赋值给对应的变量,是拷贝对象各个层级的属性,在内存中开辟一块新内存,将原对象中的所有值全部复制过去,与原对象完全脱离,修改新对象中的属性值不会影响原对象、

浅克隆举例
let a = "xu";
let b = a;
alert( b ); // 'xu'
a = "ke";
alert( b ); // 'xu'

// 在这段代码中,把a赋值给b,当a的值发生变化时,并不影响b


let arr1 = [1, 2, 3];
let arr2 = arr1;
console.log( arr2 );  // [ 1, 2, 3]
arr1[0] = 2;
console.log( arr2 );  // [ 2, 2, 3]

// 在这段代码中,把arr1赋值给arr2,当arr1的值改变时,arr2对应的值也会改变



浅克隆实现方法:
  1. es6 拓展运算符
const obj ={
	name:"xuke",
	age:22
}
const obj2 = {...obj}
console.log(obj2.name) //xuke
  1. for循环遍历
let obj = {
	name:"xuke",
	age:22
}
function clone(obj ){
	const result = {}
	for(let key in obj){
		result[key] = obj[key];
	}
	return result 
}
let obj2 = clone(obj)
obj.name = "xiannv"
console.log(obj2.name) //xuke
console.log(obj2==obj) //false

obj2不会受obj的影响,因为被克隆的都是·基本数据类型,被存到中的东西,

如果obj中存在引用数据类型的话:

let obj ={
	name:"xuke",
	age:22,
	hobby:{
		first:"eat",
		second:"sleep"
	}
	
}
function clone(obj ){
	const result = {}
	for(let key in obj){
		result[key] = obj[key];
	}
	return result 
}
let obj2 = clone(obj)
obj.hobby.first= "play"
console.log(obj2.hobby.first) //play
console.log(obj2==obj) //false

我们可以看到obj2复制的obj中含有引用数据类型,我们修改了obj中的引用数据类型时,obj2中的也会改变,数据在复制的时候是把obj中的引用数据类型地址一起复制过去了,所以objobj2使用的是一个地址,所以obj2会受影响,我们想要不受影响就要使用深克隆的方法。

深克隆实现方法:
  1. JSON.parse(JSON.stringify())实现深度克隆
let obj ={
	name:"xuke",
	age:22,
	hobby:{
		first:"eat",
		second:"sleep"
	}
}

let obj2 = JSON.parse(JSON.stringify(obj))
obj.hobby.first= "play"
console.log(obj2.hobby.first) //eat
console.log(obj2==obj) //false

JSON.parse(JSON.stringify())实现深度克隆的弊端:

1.对象中的方法不能进行copy,会自动忽略
2.对象中的Date时间不能进行copy, JSON.stringify方法会将日期自动转换为常规日期格式

3.正则表达式不能copy , JSON.stringify方法会将正则变为空对象

解决方法,用方法2将这些过滤掉:
2. 用递归实现深克隆

let obj ={
	name:"xuke",
	age:22,
	hobby:{
		first:"eat",
		second:"sleep"
	}
}
function clone(obj ){
	// 过滤特俗情况
	if(obj===null) return obj
	if(typeof obj !=='object') return obj
	if(obj instanceof RegExp){
		return new RegExp(obj)
	}
	if(obj instanceof Date){
		return new Date(obj)
	}
	let newObj = new obj.constructor
	for(let key in obj){
		if (obj.hasOwnProperty(key)) {
			newObj[key] = clone(obj[key] )
		}
	}
	return newObj 
}
let obj2 = clone(obj)
obj.hobby.first= "play"
console.log(obj2.hobby.first) //eat
console.log(obj2==obj) //false

使用:当copy源中没有引用类型,方法,正则,日期等值,只是普通的数据类型时,我们就可以用浅拷贝的方法,反之用深拷贝

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值