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 集合的深复制与浅复制
概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制 ...
随机推荐
- windows7 + iis7 + fastcgi + php5 + netbeans + xdebug 调试 php
Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具),可以用来跟踪,调试和分析PHP程序的运行状况. windows7 + iis7 + fastcgi + php5 + netbe ...
- 虚拟机VMWare的操作
软件测试工程师需要搭建测试环境——虚拟机操作. VMWare Workstation虚拟机:模拟真实的环境进行各种试验和操作,启动之后,会占用一部分的系统资源. 官网安装:http://www.vmw ...
- ASP.net发布项目引用了C++DLL后页面提示找不到指定模块的异常
1.在引用C++dll的DllImport位置指定dll位置 [DllImport(@"C:\Windows\System32\DDyn_Method.dll", EntryPoi ...
- 【VS开发】开发最小化到托盘的功能
在VC++中,想实现最小化MFC程序的时候,最小化到系统托盘,需要调用NOTIFYICONDATA类 下面我们就来讲解一下如何简单实现一个系统托盘我们以对话框程序为列 第一步:在Dlg类中//定义一个 ...
- MySQL的join on和 where 的执行顺序和区别,以及各种连接说明
目录 1.各种连接的解读说明: 1.1.各种连接的含义和说明 1.1.1 所有连接分类 1.1.2 left join 和 left outer join 区别 1.2.神图参考 1.4.一些参考说明 ...
- windows环境下安装: VMware 15 + centos 7
第一步: 下载 centos7 http://isoredirect.centos.org/centos/7/isos/x86_64/ 选择阿里云镜像下载,速度最快 注意: 尽量使用下载工具下载, ...
- 01. xadmin表单的自定义排版
xadmin表单的自定义布局(重写 get_form_layout()) apps.courses.adminx.py class NewCoursesAdmin(object): list_disp ...
- 原生xgboost中如何输出feature_importance
网上教程基本都是清一色的使用sklearn版本,此时的XGBClassifier有自带属性feature_importances_,而特征名称可以通过model._Booster.feature_na ...
- box-shadow 用法总结
一.基础知识 box-shadow 属性向框添加一个或多个阴影. 语法 box-shadow: offset-x offset-y blur spread color inset; box-shado ...
- Python-05-字符串格式化
一.百分号方式 %[(name)][flags][width].[precision]typecode (name) 可选,用于选择指定的key flags 可选,可供选择 ...