详解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 相关文章推荐
根据地区不同显示时间的javascript代码
Aug 13 Javascript
调用js时ie6和ie7,ff的区别
Aug 19 Javascript
jquery.combobox中文api和例子,修复了上面的小bug
Mar 28 Javascript
js 自制滚动条的小例子
Mar 16 Javascript
JS完整获取IE浏览器信息包括类型、版本、语言等等
May 22 Javascript
jquery仿百度经验滑动切换浏览效果
Apr 14 Javascript
vue-resource 拦截器(interceptor)的使用详解
Jul 04 Javascript
JS对象与json字符串相互转换实现方法示例
Jun 14 Javascript
layui table 复选框跳页后再回来保持原来选中的状态示例
Oct 26 Javascript
Vue根据条件添加click事件的方式
Nov 09 Javascript
ES6中Set和Map用法实例详解
Mar 02 Javascript
Vue实现返回顶部按钮实例代码
Oct 21 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 深入理解strtotime函数的使用详解
2013/05/23 PHP
php基于表单密码验证与HTTP验证用法实例
2015/01/06 PHP
php操作memcache缓存方法分享
2015/06/03 PHP
PHP并发场景的三种解决方案代码实例
2021/02/27 PHP
Ajax一统天下之Dojo整合篇
2007/03/24 Javascript
浅析jQuery(function(){})与(function(){})(jQuery)之间的区别
2014/01/09 Javascript
JQuery拖动表头边框线调整表格列宽效果代码
2014/09/10 Javascript
js防止DIV布局滚动时闪动的解决方法
2014/10/30 Javascript
Jquery使用小技巧汇总
2015/12/29 Javascript
JavaScript中数组去除重复的三种方法
2016/04/22 Javascript
js操作XML文件的实现方法兼容IE与FireFox
2016/06/25 Javascript
JS实现根据用户输入分钟进行倒计时功能
2016/11/14 Javascript
jQuery插件zTree实现删除树节点的方法示例
2017/03/08 Javascript
vue-cli webpack 开发环境跨域详解
2017/05/18 Javascript
webpack教程之webpack.config.js配置文件
2017/07/05 Javascript
python中的五种异常处理机制介绍
2014/09/02 Python
Python IDLE 错误:IDLE''s subprocess didn''t make connection 的解决方案
2017/02/13 Python
python中numpy.zeros(np.zeros)的使用方法
2017/11/07 Python
python pandas库中DataFrame对行和列的操作实例讲解
2018/06/09 Python
pandas筛选某列出现编码错误的解决方法
2018/11/07 Python
在python环境下运用kafka对数据进行实时传输的方法
2018/12/27 Python
使用Python实现将list中的每一项的首字母大写
2019/06/11 Python
Python进程间通信 multiProcessing Queue队列实现详解
2019/09/23 Python
如何在windows下安装Pycham2020软件(方法步骤详解)
2020/05/03 Python
python 实现非极大值抑制算法(Non-maximum suppression, NMS)
2020/10/15 Python
HTML5样式控制示例代码
2013/11/27 HTML / CSS
美国批发零售网站:GearXS
2016/07/26 全球购物
Speedo澳大利亚官网:全球领先游泳品牌
2018/02/04 全球购物
波兰购物网站:MALL.PL
2019/05/01 全球购物
家电业务员岗位职责
2014/03/10 职场文书
高级工程师英文求职信
2014/03/19 职场文书
市场营销调查计划书
2014/05/02 职场文书
导游词欢迎词
2015/02/02 职场文书
2015年办公室工作总结范文
2015/03/31 职场文书
小学校本教研总结
2015/08/13 职场文书
Python 操作pdf pdfplumber读取PDF写入Exce
2022/08/14 Python