00:00
哈喽,大家好,这个小节我们接来做声拷贝。我们这次的目标呢,就是要解决循环引用这个问题。那么首先我们先来分析一下这个第一步可用二第二种方式,它为什么不能够解决深拷贝的问题啊,不能够解决这个循环引用的问题。那么首先我们先来看一看,在进行了循环引用设置之后,Obj这个结构它的样子是什么样子的啊,OK,咱们点开刷新页面瞅一眼。设置这个。情形是这样子的,B里边把C属性放了进来。C里边加了一个属性,把B的值放了进来。我们看看控制台。点开浏览器。点开它。看这B里边把C放了进来。这个对象就是C点值。而C当中呢,又把B。这个数组放了进来。那么这个时候你可以看一看,咱们就以B来看啊,来看看他这个情形,B里边有C,点开C之后,C里边有B啊,你中有我是我中有你。
01:11
那么我们再来看看代码。他在执行过程当中的一个情形。首先obj这是第一个参数。啊,然后传进来。大家可以想象一下啊,就是我们在调的时候,它肯定是第一不可能二。然后把obj放进来。OBD放进来之后。这个对象。它呢是满足条件的。所以说创建容器,它应该是一个对象。然后呢,开始便利这个对象。然后第一次循环。它的K值应该是A。然后呢,这个target k的值呢,应该是一。然后呢,因为呢,当前这个。对象身上本身是有这个属性的,所以说呢,他这个条件也是满足的。然后往result结果。
02:01
对象当中去添加A属性,这里没什么问题。这是第一次循环就完成了。下边的话,第二次循环K值变成了B。而target。它的这个B啊,就是他给的B啊,就这个这个地方,它只是一个数组。而且这个数组的话还比较特殊啊,还比较特殊,所以说在这个时候执行时。啊,然后呢,开始又对这个数据做了一次。我这样写并不是很准确,因为什么?因为下边还做了一个这样的push,我们点开控制台。它真正的第一不可用的其实是它。拿过来。好,所以在第二次循环的时候。啊,开始呢,去克隆这个数据。克隆这个数据呢,然后进到一个新的上下文当中。然后去判断这玩意儿它是不是个对象,哎,你看是对象满足条件进来。
03:01
Result呢啊,它那应该是要根据类型去做一个容器设置啊,应该把它变成一个中括号。啊,然后也没有问题,然后开始便利啊。变列的时候呢,发现第一个它是个E,是个字符串,那好,既然是E的话,再调D,不可能返回结果也是个E。所以说这个result里边第一个元素就已经成了E的。二三也没啥问题,F和G,但是呢,这第四个就出问题了。第四个一看哟,这是个对象啊,咱们需要对它做一个克隆啊,升拷贝啊,于是乎再次去调第一步克隆。那么此时它的参数就发生了变化。它参数长什么样子呢?它参数长这个样子。啊,这是。在克隆到这个位置的时候。它第一步可动,再次去执行参数变成了它。变成它之后呢,好这时候呢,注意啊,它给的值已经变成了谁啊这个对象了。
04:00
好,还是接接着做判断吧,判断这块满足条件。那好,容器先把它变成一个对象。然后开始便利这个对象吧,For音循环K第一个值H。啊,然后呢,这块也满足条件,往造里边去放H这个属性。然后因为你这块这个键值是个20。你想想20 20第一步可用的话,第一个不满足,所以说直接走这儿返回一个新20。所以说就把20这个值呢,存到了result。啊,这一个对象当中。但是呢,这个存完之后呢,下边就来问题了,接这个属性怎么办?比如说K的值等于接了啊循环到这儿。Target接的值是谁呀?是一个数组。所以你还要对他再次去进行深拷贝。参数。参数是谁呢?参数就是它。啊,就是它。
05:01
又回来了。你看这。啊,然后呢,回来之后呢,你想想这个运行到这儿之后,它又它又又来。啊,他又来。复制呀,这个复制不了啊,我们再去贴一份。打开。然后把这个对象咱们再拿,再把它拿过来。他就没有穷尽了。无穷无尽这样的便利下去。这就是为什么咱们第二种方式,它不能够去解决循环引用问题的一个原因。那我们要想解决这个问题怎么办呢?哎,我们说了啊,这个地方。其实问题出在哪儿呢?出在于我们之前已经克隆过。这个对象的。到这儿你又让我克隆。啊,问题就出在这儿,我们只要保证这个数据克隆过一次,后续就不再克隆。这个问题就可以解决。那如何保证这个数据我只克隆一次呢?
06:00
我们就得拿一个容器去做保存。下一次再克隆的时候呢,我去判断一下之前我是不是克隆过。如果克隆过,就直接把之前克隆结果拿回来。拿回来之后直接返回,我们就不再去单独再次去创建新的容器去克隆了。然后这样的话,问题就可以解决。好了,首先的话,我们先把这个图呢先给大家。先那个隐藏起来。啊,关闭。然后呢,把第一步二代码咱复制一份。放到下边来。把名字改一改啊,咱们写个三。这块也是一样,来个deep。然后目前来运行的话,它结果肯定是会出问题的啊无限地柜。啊,那咱们怎么解决呢?咱们可以这样子加一个容器。借助于map啊,加一个容器,Map是呢?是什么呢?是映射。啊,其实跟对象很像,不过它的键值可以是对象。啊,可以是任意类型。
07:00
好了,有了map之后。那这样一来的话,我们在进行。新的容器创建出来之后,我们可以将。新的这个结果。存储到。容器中。怎么个存法呢?就是map.set。建名,我们就是target。然后呢,见值就是这个result。大家同学可能会说,这是干啥呢?我来举个例子。比方说,刚才我们要克隆这个数组了,举个例子。啊,我要克隆它了。要克隆它的话,我就把这一个数组作为键名存进去。然后呢,把result做兼值放进来。那么result是谁啊?就是我们后续会克隆出来一个跟它一模一样的一个数据。那么这样一来,如果说我扩充完这个之后呢,待会儿又出来一个EFG。跟它值是一模一样的,我就不需要再去重新创建了。
08:01
啊,直接从map当中直接取出来缓存这个数据就可以了。是这样一个思路。好了,我先把它关闭。这是对数据呢,对我们克隆的数据做了一个缓存。好了,缓存完毕之后呢,等下次我们再取数据的时候。注意啊,在这儿啊,我们。在进行克隆数据。克隆数据之前。要先进行一个判断。判断什么呢?判断这个数据。之前是否克隆过?啊,我们可以先接收一下let catch等于一个map.get。把target放进来。获取一下,如果说咱之前呢。克隆过了,那就没有必要再去克隆了,直接return这个catch就可以了。这样的话,问题就解决了。当然了,在这咱们还有一个地方需要调整一下啊,那就是这个地方啊,应该是三,不应该是二。
09:05
而且这个map我们每一次都要把它传进去。因为每一次在调用第一步克隆三的时候,都得借助于这个map,它来判断数据到底之前有没有克隆过。所以说这一步很重要。好了,那完成之后咱们来看看效果怎么样。点开浏览器,刷新页面。可以看到没有报错,然后咱们把代码也都打开。把它先先去掉。切过来刷新页面。然后点开。看循环引用的问题有没有解决,点开它。点开它,点开它,然后点开它没有问题。好了,那么到这儿的话。关于解决循环引用这个问题的声拷贝我们就已经完成了。
我来说两句