JS 中深拷贝与浅拷贝以及实现方式
作者:互联网
浅谈JS 中深拷贝与浅拷贝,以及实现方式。
最近在做一些练习的时候因为js的深浅拷贝的问题踩过一些坑,这应该也是初学者们经常犯错一个点,在此记录加深记忆。
总所周知,数据大体可以分为两种数据类型,一种是基本数据类型,数据结构不是很复杂,单独可以存在内存中就可以,而另一种是复杂数据类型,也叫引用数据类型,例如数组和对象,是放在栈中存储的,而基本数据类型是放在内存中的,不涉及深拷贝和浅拷贝,也可以说基本数据类型的拷贝都是深拷贝。
简单来说浅拷贝主要拷贝的是对象的引用值,当改变对象的值,另一个对象的值也会发生变化。
可以看出:浅拷贝其实拷贝的是它的引用地址,let a = [0,1,2,3,4,5]; b = a;
b拷贝了a在栈中的堆地址,都指向a在堆中的属性值,当a数组放生改变时,b属性值也会改变,因为b也指向相同的堆内存。
深拷贝主要是将另一个对象的属性值拷贝过来之后,另一个对象的属性值并不受到影响,因为此时它自己在堆中开辟了自己的内存区域,不受外界干扰。
我们看一个例子,let a = 1(这里的1指的是复杂的Object类型数据)命令会在栈内存中开辟一块区域,之后拷贝一个a对象给b,如图所示
我们可以看到,在栈内存中也为b开辟了一块内存区域,此时a,b的赋值互不干扰,当改变a对象属性值时b不受影响,这其实就完成了我们所谓的深拷贝。
实现深拷贝
1.通过 JSON 对象实现深拷贝
function deepClone(obj) {
const obj = JSON.stringify(obj);
objClone = JSON.parse(_obj);
return objClone;
}
这个方法是先将要拷贝的数据线转换成字符串,来开辟一个新的地址用以储存新的数据
因为这种方式导致存在缺陷,无法实现对对象中方法(function)以及undefined深拷贝,而且对date类型不太友好。
2.Object.assign()拷贝
const obj = {
name: 'pink老师',
age: 18
};
const obj2 = Object.assign(obj1);
注意:
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
3.使用递归的方式实现深拷贝
function copy(obj){
let newobj = null; //声明一个变量用来储存拷贝之后的内容
//判断数据类型是否是复杂类型,如果是则调用自己,再次循环,如果不是,直接赋值即可,
//由于null不可以循环但类型又是object,所以这个需要对null进行判断
if(typeof(obj) == 'object' && obj !== null){
//声明一个变量用以储存拷贝出来的值,根据参数的具体数据类型声明不同的类型来储存
newobj = obj instanceof Array? [] : {};
//循环obj 中的每一项,如果里面还有复杂数据类型,则利用递归再次调用copy函数
for(var i in obj){
newobj[i] = copy(obj[i])
}
}else{
newobj = obj
}
return newobj;
}
实现思路:
1.将要拷贝的数据 obj 以参数的形式传参
2.声明一个变量 来储存我们拷贝出来的内容
3.判断 obj 是否是引用类型数据,如果不是,则直接赋值即可( 可以利用 obj instanceof Type 来进行判断),
4.由于用 instanceof 判断array 是否是object的时候,返回值为true, 所以我们在判断的时候,直接判断obj 是否是Array 就可避免这个问题
5.根据判断的不同类型,再给之前的变量赋予不同的类型: [ ] : { }
6.循环obj 中的每一项,如果里面还有复杂数据类型,则直接利用递归再次调用copy函数
7.最后 将 这个变量 return 出来即可
4.lodash函数库实现深拷贝
lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝
标签:obj,对象,数据类型,JS,中深,内存,拷贝,属性 来源: https://blog.csdn.net/q130334/article/details/106905657