别和我说你还不会深浅拷贝了~

102 阅读3分钟

一、浅拷贝

浅拷贝简单来说只会对js简单的数据类型进行拷贝,不会对引用类型进行拷贝。针对引用类型数据他只会复制内存地址,而不是复制对象的本身,新旧对象会指向同一个内存地址。

1.1 展开运算符

一般在做对象的浅拷贝的时候,我们都会使用展开运算符来实现。 const arr = {...需要被浅拷贝的对象},这样就能实现浅拷贝了。

1.2 Object.assign

这个方法可以用来对象的合并或者是浅拷贝,const obj = Object.assign({}(拷贝在这个空对象里面),需要被拷贝的对象)。

深拷贝

深拷贝和浅拷贝最大的区别是深拷贝能对引用类型进行复制,而不是和旧对象共用内存地址。js没有提供内置的实现深拷贝的方法,因为深拷贝有点太消耗内存了,在平常的过程中可以使用lodash。

1.1 JSON.stringify实现深拷贝

大部分前端小伙伴包括我自己也喜欢使用该方法实现深拷贝,但是该方法是有一定的缺陷的,他会忽视掉一些数据类型,例如:当对象中有一个方法,我们用了该方法会发现拷贝的对象不存在该方法了,在比如被拷贝的对象有个value是undefine的,我们拷贝过来以后会发现undefine对应的key都不存在。

code.png 可以看到,原始对象info里面存在bar函数和test,但是用了stringify方法后不存在该函数和值。 code.png

1.2 递归实现深拷贝

在实现深拷贝之前,我们需要先想一想那些类型是需要进行深拷贝的,列入:对象、数组、函数。我们如何去判断传递过来的数据就是这三种呢? 我们可以使用typeof方法,但是typeof有一个缺陷就是null也会被认为是一个空对象,因此我们在判断的过程中应该加上对空值的限制以及函数的判断处理。

封装了一个isObject方法,如图所示可以正确的判断数据并返回对应的值。 code.png 接下来我们就开始递归实现深拷贝了。

code.png

但是我们想要对数组做深拷贝的时候,上面的代码还不能做到,如图所示新拷贝出来的数组跟上面的完全不一样,这是因为上面我们直接创建的是一个对象,因此我们想要对数组进行优化就不能直接创建对象,需要判断是否为数组,是数组的话就复制为数组。

code.png

把直接新建一个对象改为const newObj = Array.isArray(targetValue) ? [] : {},这样就可以完美实现了。

code.png

最后一个优化小点,就是针对函数我们不需要对他进行深拷贝,因为函数本身就是用来执行的,没必要在进行拷贝。

//判断是否为函数 if (typeof targetValue === "function"> {return targetValue}

简单的深拷贝就实现出来了,当然还有许多的不足包括不能对Symbol类型、Map类型进行拷贝(能力有限哈哈)。