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()实现深拷贝

猜你喜欢

转载自blog.csdn.net/q130334/article/details/106905657