博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS深拷贝总结
阅读量:6511 次
发布时间:2019-06-24

本文共 1853 字,大约阅读时间需要 6 分钟。

JS的原生不支持深拷贝,
Object.assign
{...obj}都属于浅拷贝,下面我们讲解如何使用JS实现深拷贝。

JSON.sringify 和 JSON.parse 

这是JS实现深拷贝最简单的方法了,原理就是先将对象转换为字符串,再通过JSON.parse重新建立一个对象。 但是这种方法的局限也很多:

  • 不能复制function、正则、Symbol
  • 循环引用报错
  • 相同的引用会被重复复制

我们依次看看这三点,我们测试一下这段代码:

let obj = {             reg : /^asd$/,    fun: function(){},    syb:Symbol('foo'),    asd:'asd'}; let cp = JSON.parse(JSON.stringify(obj));console.log(cp);复制代码

结果:

可以看到,函数、正则、Symbol都没有被正确的复制。

如果在JSON.stringify中传入一个循环引用的对象,那么会直接报错:

在说第三点之前,我们看看这段代码:

let obj = {  asd:'asd' }; let obj2 = {
name:'aaaaa'};obj.ttt1 = obj2;obj.ttt2 = obj2;let cp = JSON.parse(JSON.stringify(obj)); obj.ttt1.name = 'change'; cp.ttt1.name = 'change';console.log(obj,cp);复制代码

在原对象 obj 中的 ttt1ttt2 指向了同一个对象 obj2,那么我在深拷贝的时候,就应该只拷贝一次 obj2 ,下面我们看看运行结果:

我们可以看到(上面的为原对象,下面的为复制对象),原对象改变 ttt1.name 也会改变 ttt2.name ,因为他们指向相同的对象。

但是,复制的对象中,ttt1 和 ttt2 分别指向了两个对象。复制对象没有保持和原对象一样的结构。因此,JSON实现深复制不能处理指向相同引用的情况,相同的引用会被重复复制。

递归实现

JS原生的方法不能很好的实现深复制,那么我们就动手实现一个。

思想非常简单:对于简单类型,直接复制。对于引用类型,递归复制它的每一个属性。

我们需要解决的问题:

  • 循环引用
  • 相同引用
  • 不同的类型(笔者仅实现了数组和对象的区分)

实现代码:

function deepCopy(target){ let copyed_objs = [];//此数组解决了循环引用和相同引用的问题,它存放已经递归到的目标对象     function _deepCopy(target){         if((typeof target !== 'object')||!target){
return target;} for(let i= 0 ;i
{ if(obj[key]){ return;} obj[key] = _deepCopy(target[key]); }); return obj; } return _deepCopy(target);}复制代码

copyed_objs 这个数组存放的是已经递归过的目标对象。在递归一个目标对象之前,我们应该检查这个数组,如果当前目标对象和 copyed_objs 中的某个对象相等,那么不对其递归。

这样就解决了循环引用和相同引用的问题。

测试一下代码:

var a = {    arr:[1,2,3,{
key:'123'}],//数组测试};a.self = a;//循环引用测试a.common1 = {
name:'ccc'};a.common2 = a.common1;//相同引用测试var c = deepCopy(a);c.common1.name = 'changed';console.log(c);复制代码

结果:

可以看到,前文提到的问题都已经解决。

最后补充:

本文实现的深拷贝仅仅是解决了深复制的关键问题,还需要针对不同的数据类型进行完善。

转载于:https://juejin.im/post/5b20c9f65188257d7d719c1c

你可能感兴趣的文章