详解JavaScript对象的深浅复制


Posted in Javascript onMarch 30, 2017

前言

从层次上来看,对象的复制可以简单地分为浅复制和深复制,顾名思义,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,对象的深复制会复制对象中层层嵌套的对象的属性。

在复制对象时,除了要复制对象的属性外,还要兼顾到是否保留了对象的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

详解JavaScript对象的深浅复制

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;
}

先用上面的例子测试:

详解JavaScript对象的深浅复制

棒!可以正确实现多维数组的复制,再看是否能实现函数和正则的复制:

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();

详解JavaScript对象的深浅复制

圆满完成!!

稍加整理,我们就可以得到一个较为通用的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;
}

结语

面向对象的编程语言,其核心是对象,因此深入了解对象的相关操作,纵向比较异同,对学习过程是极有好处的。

以上所述是小编给大家介绍的JavaScript对象的深浅复制,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
js通过地址栏给action传值(中文乱码全是问号)
May 02 Javascript
jquery操作下拉列表、文本框、复选框、单选框集合(收藏)
Jan 08 Javascript
在jquery boxy中添加百度地图坐标拾取注意流程
Apr 03 Javascript
js css 实现遮罩层覆盖其他页面元素附图
Sep 22 Javascript
Jquery实现textarea根据文本内容自适应高度
Apr 03 Javascript
JQuery中DOM事件绑定用法详解
Jun 13 Javascript
在JavaScript中使用开平方根的sqrt()方法
Jun 15 Javascript
JavaScript字符串删除重复字符的方法
Dec 25 Javascript
jQuery使用contains过滤器实现精确匹配方法详解
Feb 25 Javascript
微信小程序去哪里找 小程序到底如何使用(附小程序名单)
Jan 09 Javascript
vue实现打地鼠小游戏
Aug 21 Javascript
使用Cargo工具高效创建Rust项目
Aug 14 Javascript
js实现不提示直接关闭网页窗口
Mar 30 #Javascript
jquery中关于bind()方法的使用技巧分享
Mar 30 #jQuery
JavaScript实现弹出广告功能
Mar 30 #Javascript
JavaScript如何一次性展示几万条数据
Mar 30 #Javascript
ECMAScript6--解构
Mar 30 #Javascript
js图片放大镜效果实现方法详解
Oct 28 #Javascript
js a标签点击事件
Mar 30 #Javascript
You might like
php模块memcache和memcached区别分析
2011/06/14 PHP
解析yii数据库的增删查改
2013/06/20 PHP
开启PHP Static 关键字之旅模式
2015/11/13 PHP
利用JQuery和JS实现奇偶行背景颜色自定义效果
2012/11/19 Javascript
window.open打开页面居中显示的示例代码
2013/12/27 Javascript
jquery幻灯片插件bxslider样式改进实例
2014/10/15 Javascript
jquery实现相册一下滑动两次的方法
2015/02/09 Javascript
jQuery实现的网页竖向菜单效果代码
2015/08/26 Javascript
jQuery实现可关闭固定于底(顶)部的工具条菜单效果
2015/11/06 Javascript
nodejs创建简易web服务器与文件读写的实例
2017/09/07 NodeJs
原生JS上传大文件显示进度条 php上传文件代码
2020/03/27 Javascript
使用Typescript和ES模块发布Node模块的方法
2020/05/25 Javascript
vue 添加和编辑用同一个表单,el-form表单提交后清空表单数据操作
2020/08/03 Javascript
[03:04]2018年国际邀请赛典藏宝瓶&莱恩声望物品展示 片尾有彩蛋
2018/06/04 DOTA
[01:04:49]KG vs LGD 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
python文件和目录操作方法大全(含实例)
2014/03/12 Python
python使用urllib2提交http post请求的方法
2015/05/26 Python
Python创建二维数组实例(关于list的一个小坑)
2017/11/07 Python
Python使用requests发送POST请求实例代码
2018/01/25 Python
pandas.DataFrame选取/排除特定行的方法
2018/07/03 Python
python中字典按键或键值排序的实现代码
2019/08/27 Python
python实现文件的分割与合并
2019/08/29 Python
Python实现报警信息实时发送至邮箱功能(实例代码)
2019/11/11 Python
python pygame实现挡板弹球游戏
2019/11/25 Python
如何更改 pandas dataframe 中两列的位置
2019/12/27 Python
tensorflow estimator 使用hook实现finetune方式
2020/01/21 Python
pytorch实现保证每次运行使用的随机数都相同
2020/02/20 Python
Django扫码抽奖平台的配置过程详解
2021/01/14 Python
土地转让协议书范本
2014/04/15 职场文书
计算机系统管理员求职信
2014/06/20 职场文书
销售员未完成销售业绩的检讨书
2014/10/12 职场文书
2014年销售助理工作总结
2014/12/01 职场文书
农村房屋租赁合同(范本)
2019/07/23 职场文书
MySQL窗口函数的具体使用
2021/11/17 MySQL
Java设计模式之代理模式
2022/04/22 Java/Android
Linux安装Docker详细教程
2022/07/07 Servers