前言

所谓深复制与浅复制(深拷贝与浅拷贝),乍一听感觉听高大上,像是一个非常难理解的概念,其实我们平常项目开发都是在用的,只是你可能不知道该怎么叫它的名字而已,就像你听熟了一首歌,就是不知道这首歌叫什么名字一样。

在javascript中有两种数据类型,一种是基本类型,另一种是引用类型,今天说讨论的深复制与浅复制就是和这两种数据类型有直接的关系。

1、基本类型的复制

js种的基本类型有Number Boolean  String  undefined null这五类,在声明的时候,基本类型的数据都是存放在栈内存中,如下图:

首先声明的a变量会存储在栈内存里,然后又在栈内存里复制了一个a并且赋值给b,此时栈内存里汇总新分配一个内存给不,a和b的值都是abc;然后给b重新赋值,由于a和b都是独立存在的两个变量,所以两个值任何一个变化,都不会影响另外一个变量的值;通俗点来说,就是你有一个叫做a的word文档,原本在D盘里,你把它复制了一份仍在了桌面上,这个时候你对两个文件的编辑并不会相互影响,如上图。

 2、引用类型的复制

引用类型,即object,function的值都是存在堆内存中,栈内存中通过指针指向这个值在堆中的地址,而对于引用类型来说普通的赋值操作只是将指针的地址复制了一份给新的变量,属于浅复制,如下图:

这里将arr赋值给arr1,其实就是复制了arr的指针,所以arr1的指向地址和arr是一样的,这样不管操作arr还是arr1都会改变堆中数组的值,打印arr或者arr1都是改变后的值,这种情况只是改变了指针的指向,还用文件复制的形式来解释的话就是复制了一个文件的快捷方式,把它仍在桌面上,打开的仍然是源文件,如上图。

但是现在有一个需求,就是后台请求过来的json对象,在对其处理之前需要拷贝一份以方便其他开发人员再开发,如果我们用上面的赋值方式复制一份出来肯定是不行的,这样的话你下面对数据的处理也会改变源数据的值,那应该怎么处理呢?看下面代码

 function copy(obj) {
let Tobj = {}
for(var key in obj) {
Tobj[key] = obj[key] // 遍历复制属性
}
return Tobj
} var obj = {
name: "MrGao",
age: 24
};
var obj1 = copy(obj);
obj1.name = "MrBone"
console.log(obj.name) // "MrGao"
console.log(obj1.name) // "MrBone"

这样基于重新复制了一份数据出来,而且下面如果你对复制出来的数据进行修改,也不会影响源数据

但是,如果出现下面这种情况还是会有问题

 var obj = {
name: "MrGao",
age: 24,
skill: {
work: "javascript",
life: "singer"
}
};
function copy(obj) {
let Tobj = {}
for(var key in obj) {
Tobj[key] = obj[key]
}
return Tobj
}
var obj1 = copy(obj);
obj1.skill.work = "java"
console.log(obj.skill.work) // java
console.log(obj1.skill.work) // java

如此看来,值还是都改变了,上面两者只是obj中多了一个skill对象而已,由于遍历复制的只是obj中的属性,所以obj.skill作为一个引用类型对象,也只是复制了一个指针过去,所以当obj1中的skill发生了变化,obj中的skill也会变化,那么如何解决这个问题呢?

 var obj = {
name: "MrGao",
age: 24,
skill: {
work: "javascript",
life: "singer"
}
};
function copy(obj) {
let Tobj = {}
for(var key in obj) {
if (typeof(obj[key]) == 'object') {
Tobj[key] = copy(obj[key])
} else {
Tobj[key] = obj[key]
}
}
return Tobj
}
var obj1 = copy(obj);
obj1.skill.work = "java"
console.log(obj.skill.work) // javascript
console.log(obj1.skill.work) // java

为了方便理解,这里只考虑到传入的值为obj,如此,当遍历到key的值为'object'类型时,这递归调用本方法,来完成对内层对象的复制。

除了上面这种方法外,还有一种方法可以实现深复制

 var obj = {
name: "MrGao",
age: 24,
skill: {
work: "javascript",
life: "singer"
}
};
var obj1 = JSON.parse(JSON.stringify(obj)); // 先将obj转为字符串再复制
obj1.skill.work = "java"
console.log(obj.skill.work) // javascript
console.log(obj1.skill.work) // java

这种方法为先将obj转化为字符串,复制的时候就会重新在栈内存中复制一份,然后JSON.parse之后重新赋值给obj1,就实现了对对象的深复制。

总结

浅复制:之前理解的是浅复制指的是对引用对象指针的复制,并没有复制其本质内容;后来对浅复制的理解为对引用对象一层复制为浅复制,而对应的深复制为以上两种对对象进行深复制的方法。

深复制:深复制就是对一个对象通过递归,或类型转换的全面复制。

对于以上纯属个人理解,如有纰漏,欢迎指正!

js中的深复制与浅复制的更多相关文章

  1. js中的深复制和浅复制

    在实际情况中经常会遇到对对象复制的问题.比如在处理项目中的一笔多结构的数据存储或者调用,这个时候你就要对对象(json)进行操作,而不同的操作根据不同的需求来定义.其中最常见最普遍的是对对象的复制,重 ...

  2. Java中对象的深复制和浅复制详解

    1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...

  3. Java中的深复制与浅复制

    1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不 复制它所引用的对象. ...

  4. C#中的深复制与浅复制

    C#中分为值类型和引用类型,值类型的变量直接包含其数据,而引用类型的变量则存储对象的引用. 对于值类型,每个变量都有自己的数据副本,对一个变量的操作不可能影响到另一个变量.如 class Progra ...

  5. Java中的clone()----深复制,浅复制

    这篇文章主要介绍了Java中对象的深复制(深克隆)和浅复制(浅克隆) ,需要的朋友可以参考下 1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他 ...

  6. js的深复制与浅复制

    什么是深复制和浅复制? 深复制和浅复制的概念只存在于对象array和数组obj上. 浅复制是:模糊复制,就是不管对方是字符串类型还是引用类型都通通复制过来.结果两个变量的内容会同时变化. 深复制是:有 ...

  7. .Net深复制、浅复制

    在.Net,大家都知道引用类型的深复制.浅复制吧. ,一般int等值类型是值类型(复制时是直接传值),一般的类(List<T>,Class)是引用类型(复制时传地址),默认是浅复制.若ob ...

  8. C++学习基础七——深复制与浅复制

    一.深复制与浅复制基本知识 深复制和浅复制,又称为深拷贝和浅拷贝. 深复制和浅复制的区别如下图1所示: 图1 图1表示的是,定义一个类CDemo,包含int a和char *str两个成员变量, 当深 ...

  9. iOS 集合的深复制与浅复制

    概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制 ...

随机推荐

  1. oraagent.bin High Memory Usage as Dependent Listener was Removed/Renamed

    Grid Infrastructure oraagent.bin process using huge amount of memory and  forking huge number of thr ...

  2. Apache Flink 开发环境搭建和应用的配置、部署及运行

    https://mp.weixin.qq.com/s/noD2Jv6m-somEMtjWTJh3w 本文是根据 Apache Flink 系列直播课程整理而成,由阿里巴巴高级开发工程师沙晟阳分享,主要 ...

  3. python web开发Django连接mysql

    需要MYSQL-python,一般情况下直接pip install window系统会报错,所以要去 https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml  ...

  4. spring 配置事务管理器

    在Spring中数据库事务是通过PlatformTransactionManager进行管理的,jdbcTemplate是不能支持事务的,而能够支持事务的是org.springframework.tr ...

  5. 【DeepCTR】

    DeepFM: https://www.jianshu.com/p/6f1c2643d31b CCPM,FGCNN: https://cloud.tencent.com/developer/artic ...

  6. 【计算机视觉】OpenCV篇(5) - 仿射变换与透视变换

    参考: 图像处理的仿射变换与透视变换(https://www.imooc.com/article/27535) http://ex2tron.wang/opencv-python-extra-warp ...

  7. SpringMVC:学习笔记(11)——依赖注入与@Autowired

    SpringMVC:学习笔记(11)——依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...

  8. JavaScript图形实例:图形的扇形变换和环形变换

    1.1  扇形变换 将如图1所示的上边长方形的图形变换为下边的扇形图形的变换称为扇形变换. 设长方形图形中任一点P1(X1,Y1)变换为扇形图形上的点P2(X2,Y2),长方形的长为X,扇形圆心坐标为 ...

  9. SPSS 2019年10月24日 今日学习总结

    2019年10月24日今日课上内容1.SPSS掌握基于键值的一对多合并2.掌握重构数据3.掌握汇总功能 内容: 1.基于键值的一对多合并 合并文件 添加变量 合并方法:基于键值的一对多合并 变量 2. ...

  10. vue 跨域简记

    0.服务端设置 app.use(function(req, res, next){ //设置跨域访问 res.header('Access-Control-Allow-Origin', '*'); r ...