JavaScript对象的深浅复制
前言
从层次上来看,对象的复制可以简单地分为浅复制和深复制,顾名思义,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,对象的深复制会复制对象中层层嵌套的对象的属性。
在复制对象时,除了要复制对象的属性外,还要兼顾到是否保留了对象的constructor属性,是否对每一种数据类型(JavaScript常见的数据类型有String,Number,Boolean,Data,RegExp,Array,Funtion,Object)都实现正确的复制。项目中,我们可以根据实际情况,决定需要实现什么样程度的复制。
本文是我在复制对象方面的一些心得总结,由浅复制到深复制,由只复制简单属性到复制Function,RegExp等复杂属性,层层递进。如有陈述不当之处,烦请指出,不胜感激。
正文
浅复制
浅复制只会依次复制对象的每一个属性,不会对这些属性进行递归复制。下面是一个简单的浅复制实现。
//对象浅复制
function shadowCopy(obj){
if(typeof obj !== 'object') return obj;
for(var prop in obj){
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
return newObj;
}
仔细观察,不难发现上述方法的缺陷:
1.不能正确实现数组的浅复制
2.复制操作丢失了对象的constructor属性
好,我们现在已经发现了问题所在,只需针对性地解决,一个还算完美的浅复制对象的方法就诞生了!
//对象浅复制
function shadowCopy(obj){
if(typeof obj !== 'object') return ;
var newObj;
//保留对象的constructor属性
if(obj.constructor === Array){
newObj = [];
} else {
newObj = {};
newObj.constructor = obj.constructor;
}
for(var prop in obj){
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
return newObj;
}
浏览器中测试一下:
var arr1 = [0,1,2];
console.log(arr1);
console.log(shadowCopy(arr1));
var arr2 = [0,1,2,[3,4,5]],
arr2Copy = shadowCopy(arr2);
console.log(arr2);
console.log(arr2Copy);
arr2Copy[3][0] = 6;
console.log(arr2[3][0]); //6
Good! 可以正确实现数组复制和并且保留constructor了,但细心的你一定发现了,浅复制后的对象的 arr2Copy[3]
和 arr2[3]
指向的是一个对象,改变其中一个,同时也会改变另一个。我们想要实现的是 复制,但这并不是复制呀!
这是浅复制的一个弊端所在,接下让我们看看深复制是怎样解决这个问题的。
深复制
深复制需要层层递归,复制对象的所有属性,包括对象属性的属性的属性....(晕~)
如果只是需要简单地复制对象的属性,而不用考虑它的constructor,也不用考虑函数,正则,Data等特殊数据类型,那这里有一个深复制的小trick,两行代码即可:
function deepCopy(obj){
if(typeof obj !== "object"){ return ;}
var str = JSON.stringify(obj);
return JSON.parse(str);
}
大多数情况下,上面的就可以满足要求了,但一些时候,我们需要把函数,正则等特殊数据类型也考虑在内,或者当前环境不支持JSON时,上面的方法也就不适用了。这时,我们可以通过递归来实现对象的深层复制,如下:
function deepCopy(obj){
if(typeof obj !== "object"){ return ;}
var newObj;
//保留对象的constructor属性
if(obj.constructor === Array){
newObj = [];
} else {
newObj = {};
newObj.constructor = obj.constructor;
}
for(var prop in obj){
if(typeof obj[prop] === 'object'){
if(obj[prop].constructor === RegExp ||obj[prop].constructor === Date){
newObj[prop] = obj[prop];
} else {
//递归
newObj[prop] = deepCopy(obj[prop]);
}
} else {
newObj[prop] = obj[prop];
}
}
return newObj;
}
先用上面的例子测试:
棒!可以正确实现多维数组的复制,再看是否能实现函数和正则的复制:
function Person(name){
this.name = name;
this.age = age;
this.search = new RegExp(name);
this.say = function(){
console.log(this.name + "今年" + this.age + "岁了");
}
}
var p1 = new Person("Claiyre",20),
p2 = deepCopy(p1);
console.log(p1);
console.log(p2);
p2.age = 22;
p1.say();
p2.say();
圆满完成!!
稍加整理,我们就可以得到一个较为通用的js对象复制函数:
function deepCopy(obj){
var newObj = obj.constructor === Array ? []:{};
newObj.constructor = obj.constructor;
if(typeof obj !== "object"){
return ;
} else if(window.JSON){
//若需要考虑特殊的数据类型,如正则,函数等,需把这个else if去掉即可
newObj = JSON.parse(JSON.stringify(obj));
} else {
for(var prop in obj){
if(obj[prop].constructor === RegExp ||obj[prop].constructor === Date){
newObj[prop] = obj[prop];
} else if(typeof obj[prop] === 'object'){
//递归
newObj[prop] = deepCopy(obj[prop]);
} else {
newObj[prop] = obj[prop];
}
}
}
return newObj;
}
结语
面向对象的编程语言,其核心是对象,因此深入了解对象的相关操作,纵向比较异同,对学习过程是极有好处的。
如果您觉得我的文章对您有帮助,请点击下方“推荐”让更多的人看到。
博客原文地址:Claiyre的个人博客 https://claiyre.github.io/
博客园地址:http://www.cnblogs.com/nuannuan7362/
如需转载,请在文章开头注明原文地址
JavaScript对象的深浅复制的更多相关文章
- 总结JavaScript对象的深浅拷贝
十四.对象的浅拷贝与深拷贝 什么是对象的拷贝? 将一个对象赋值给另外一个对象, 我们称之为对象的拷贝 什么是深拷贝, 什么是浅拷贝? 我们假设将A对象赋值给B对象 浅拷贝是指, 修改B对象的属性和方法 ...
- JavaScript 对象的深复制
对象的深复制 源对象的属性更改,不会引起复制后的对象个属性的更改 源对象的任何属性与子属性与新对象的之间没有任何引用关系 Coding: /* 对象的深复制: 1 初始化目标对象 如果没有指定目标对象 ...
- javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())
javascript 数组和对象的浅度复制和深度复制在平常我们用 ‘=’来用一个变量引用一个数组或对象,这里是‘引用’而不是复制下面我们看一个例子引用和复制是什么概念 var arr=[1,2,3,' ...
- C# Json反序列化 C# 实现表单的自动化测试<通过程序控制一个网页> 验证码处理类:UnCodebase.cs + BauDuAi 读取验证码的值(并非好的解决方案) 大话设计模式:原型模式 C# 深浅复制 MemberwiseClone
C# Json反序列化 Json反序列化有两种方式[本人],一种是生成实体的,方便处理大量数据,复杂度稍高,一种是用匿名类写,方便读取数据,较为简单. 使用了Newtonsoft.Json,可以自 ...
- JavaScript的深浅复制
JavaScript的深浅复制 为什么有深复制.浅复制? JavaScript中有两种数据类型,基本数据类型如undefined.null.boolean.number.string,另一类是Obje ...
- JavaScript对象复制(一)(转载)
在JavaScript很多人复制一个对象的时候都是直接用"=",因为大家都觉得脚本语言是没有指针.引用.地址之类的,所以直接用"="就可以把一个对象复制给另外一 ...
- 【IPHONE开发-OBJECTC入门学习】复制对象,深浅复制
转自:http://blog.csdn.net/java886o/article/details/9046273 #import <Foundation/Foundation.h> int ...
- js深浅复制
一.数组的深浅拷贝 <body> <script type="text/javascript"> var arr = ["One",&q ...
- javascript对象深拷贝,浅拷贝 ,支持数组
javascript对象深拷贝,浅拷贝 ,支持数组 经常看到讨论c#深拷贝,浅拷贝的博客,最近js写的比较多, 所以也来玩玩js的对象拷贝. 下面是维基百科对深浅拷贝的解释: 浅拷贝 One meth ...
随机推荐
- DB2 表空间监控
默认DB2 缓冲池信息监控是OFF, 需要开启(DB2表空间是由缓冲池分配的) CollBufferpool : ============ The CollBufferpool collector c ...
- udp服务器监听(多线程)
项目一:udp1111 监听的有三个文件分别为: guiHello.java 有关界面和事件响应功能 UdpFunc.java是udp类的封装:发送和接收 udpServer.java是入口函数,无实 ...
- Java编程风格学习(二)
二.格式规范 在上一篇的Java编程风格学习(一)中我们讲述了在Java编码中的一般原则,虽然这些原则并不涉及具体的代码规范,但是这些原则却是我们在Java开发过程中所应该遵循的规范与思想.今天我们将 ...
- python数据结构(一)------序列
数据结构是通过某种方式(例如对元素进行编号)组织在一起的数据元素的集合:在Python中,最基本的数据结构是序列(sequence),序列中的每个元素被分配一个序列号--即元素的位置,也称为索引. p ...
- Spark集群搭建_YARN
2017年3月1日, 星期三 Spark集群搭建_YARN 前提:参考Spark集群搭建_Standalone 1.修改spark中conf中的spark-env.sh 2.Spark on ...
- 使用Spring构建RMI服务器和客户端
上一篇文章我们实用JDK原生API构造了简单RMI应用,本篇将实用Spring框架来构造RMI的应用,实用Spring你会体验到简单,不需要那么多的条条框框,因为Spring给你做了很多封装. 项目构 ...
- .NET中的repeater简介及分页效果
Repeater控件是一个数据绑定容器控件,它能够生成各个项的列表,并可以使用模板定义网页上各个项的布局.当该页运行时,该控件为数据源中的每个项重复此布局. 配合模板使用repeater控件 若要使 ...
- 2017年最新chrome必备插件推荐
1. 上网必备 Speed dial plus新标签页, 直接替换掉chrome自带的毫无新意的新标签页,简洁优美快速,我本人非常喜欢. &lt;img src="https ...
- 在Ubuntu Linux下制作Windows 启动安装 USB盘
最近想 ,在Ubuntu上刻录个windows的安装U盘,在网上看了些资料,不过好多都说的很模糊,于是乎,我走了不少弯路.这里记录下来,希望了帮到大家. 首先你的有个USB吧,这里我们假定USB在ub ...
- Jmeter正则提取器常用的几种方式
使用jmeter的同学都知道,jmeter提供了各种各样的提取器,如jsonpath.Beanshell.Xpath.正则等!!! 我们就针对正则提取器如何使用进行说明. 举例说明:假设取sessio ...