当前位置: 首页 > news >正文

JS深拷贝总结

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<copyed_objs.length;i++){
            if(copyed_objs[i].target === target){
                return copyed_objs[i].copyTarget;
            }
        }
        let obj = {};
        if(Array.isArray(target)){
            obj = [];//处理target是数组的情况 
        }
        copyed_objs.push({target:target,copyTarget:obj}) 
        Object.keys(target).forEach(key=>{ 
            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

相关文章:

  • centos7安装
  • 万万没想到,枯燥的“机器学习”还可以这样学!
  • 被忽略的对象
  • Xtrabackup 使用stream输出并压缩备份
  • 一个UPDATE语句引发的血案
  • 机器学习中为什么要做归一化normalization
  • PermissionScope Swift4 兼容问题
  • mysql快速生成测试数据的方法,以及分页limit语句优化
  • extjs年月选择日历及通用js同步ajax调用返回json object
  • OSI--------物理层 eNSP
  • MySQL windows下cmd安装操作
  • 操作系统概述
  • “小红书”——给你一记安利
  • MFC:树形控件
  • Thrift版本管理
  • canvas 高仿 Apple Watch 表盘
  • Computed property XXX was assigned to but it has no setter
  • Elasticsearch 参考指南(升级前重新索引)
  • Js基础知识(一) - 变量
  • js算法-归并排序(merge_sort)
  • MySQL数据库运维之数据恢复
  • ReactNative开发常用的三方模块
  • vue2.0项目引入element-ui
  • vue-loader 源码解析系列之 selector
  • 七牛云假注销小指南
  • 使用docker-compose进行多节点部署
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 原生Ajax
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • 函数计算新功能-----支持C#函数
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • !$boo在php中什么意思,php前戏
  • (C++)八皇后问题
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (编译到47%失败)to be deleted
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (二)c52学习之旅-简单了解单片机
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (简单) HDU 2612 Find a way,BFS。
  • (七)Java对象在Hibernate持久化层的状态
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (四) 虚拟摄像头vivi体验
  • (原創) 未来三学期想要修的课 (日記)
  • (转) ns2/nam与nam实现相关的文件
  • (转)ORM
  • (转)菜鸟学数据库(三)——存储过程
  • (转载)虚函数剖析
  • .form文件_SSM框架文件上传篇
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .net core webapi 大文件上传到wwwroot文件夹
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .pyc文件是什么?
  • .sdf和.msp文件读取
  • @JSONField或@JsonProperty注解使用