js中的深复制与浅复制
前言
所谓深复制与浅复制(深拷贝与浅拷贝),乍一听感觉听高大上,像是一个非常难理解的概念,其实我们平常项目开发都是在用的,只是你可能不知道该怎么叫它的名字而已,就像你听熟了一首歌,就是不知道这首歌叫什么名字一样。
在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中的深复制与浅复制的更多相关文章
- js中的深复制和浅复制
在实际情况中经常会遇到对对象复制的问题.比如在处理项目中的一笔多结构的数据存储或者调用,这个时候你就要对对象(json)进行操作,而不同的操作根据不同的需求来定义.其中最常见最普遍的是对对象的复制,重 ...
- Java中对象的深复制和浅复制详解
1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...
- Java中的深复制与浅复制
1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不 复制它所引用的对象. ...
- C#中的深复制与浅复制
C#中分为值类型和引用类型,值类型的变量直接包含其数据,而引用类型的变量则存储对象的引用. 对于值类型,每个变量都有自己的数据副本,对一个变量的操作不可能影响到另一个变量.如 class Progra ...
- Java中的clone()----深复制,浅复制
这篇文章主要介绍了Java中对象的深复制(深克隆)和浅复制(浅克隆) ,需要的朋友可以参考下 1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他 ...
- js的深复制与浅复制
什么是深复制和浅复制? 深复制和浅复制的概念只存在于对象array和数组obj上. 浅复制是:模糊复制,就是不管对方是字符串类型还是引用类型都通通复制过来.结果两个变量的内容会同时变化. 深复制是:有 ...
- .Net深复制、浅复制
在.Net,大家都知道引用类型的深复制.浅复制吧. ,一般int等值类型是值类型(复制时是直接传值),一般的类(List<T>,Class)是引用类型(复制时传地址),默认是浅复制.若ob ...
- C++学习基础七——深复制与浅复制
一.深复制与浅复制基本知识 深复制和浅复制,又称为深拷贝和浅拷贝. 深复制和浅复制的区别如下图1所示: 图1 图1表示的是,定义一个类CDemo,包含int a和char *str两个成员变量, 当深 ...
- iOS 集合的深复制与浅复制
概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制 ...
随机推荐
- Django中的QuerySet查询优化之prefetch_related
转载的,做个笔记,原文链接 在数据库有外键的时候,使用 select_related() 和 prefetch_related() 可以很好的减少数据库请求的次数,从而提高性能.本文通过一个简单的例子 ...
- 改进初学者的PID-修改整定参数
最近看到了Brett Beauregard发表的有关PID的系列文章,感觉对于理解PID算法很有帮助,于是将系列文章翻译过来!在自我提高的过程中,也希望对同道中人有所帮助.作者Brett Beaure ...
- Linux虚拟机的命令分发工具。
deploy.sh工具的目的是,将一个文件,发送到其他服务器上面去. runRemoteCmd.sh工具的目的是,将一个命令,在多台服务器上执行. depoly.conf是上面两个工具的配置文件. d ...
- 组件文档系统-md-react-styleguidist
推荐指数:
- console.log()和alert()的区别
一直都是知道console.log()和alert()是有区别的,但是具体有什么区别就不清楚了,后来在权威指南里注意到了说alert()具有侵入性才来查一查两者的具体区别. 查询到的区别: alert ...
- Mysql 千万数据快速导入
最近碰到个项目,需要 千万条数据入库的问题,有原本的 类 csv 文件导入, 统计了下 数据行大概有 1400W 行之多 二话不说, 建表,直接 load LOAD DATA LOCAL INFIL ...
- [转帖]什么是UWB?UWB有什么用?
什么是UWB?UWB有什么用? https://www.sohu.com/a/224891573_531173 小米碰传 就是 UWB吧? 2018-03-05 17:02 UWB在早期被用来应用在近 ...
- JWT知识整理
JSON Web Token:(https://jwt.io/) JSON Web Token(JWT)是一个开放式标准(RFC 7519),它定义了一种紧凑(Compact)且自包含(Self-co ...
- Java的设计模式(5)-- 策略模式
定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换,本模式使得算法可以独立于使用它的客户而变化.策略模式包括以下三种角色 策略(Strategy):策略是一个接口,该接口定义若干个算法标识, ...
- 剑指offer41:所有和为S的连续正数序列,例如,有多少种连续的正数序列的和为100
1 题目描述 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数).没多久 ...