详解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 相关文章推荐
20款非常优秀的 jQuery 工具提示插件 推荐
Jul 15 Javascript
JS 加入收藏夹的代码(主流浏览器通用)
May 13 Javascript
JavaScript函数使用的基本教程
Jun 04 Javascript
10个JavaScript中易犯小错误
Feb 14 Javascript
jQuery获得字体颜色16位码的方法
Feb 20 Javascript
微信小程序注册60s倒计时功能 使用JS实现注册60s倒计时功能
Aug 16 Javascript
jQuery条件分页 代替离线查询(附代码)
Aug 17 jQuery
vue使用监听实现全选反选功能
Jul 06 Javascript
Vue中使用canvas方法总结
Feb 12 Javascript
vue keep-alive列表页缓存 详情页返回上一页不刷新,定位到之前位置
Nov 26 Javascript
JS检索下拉列表框中被选项目的索引号(selectedIndex)
Dec 17 Javascript
在vue中使用回调函数,this调用无效的解决
Aug 11 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
thinkPHP订单数字提醒功能的实现方法
2016/12/01 PHP
OAuth认证协议中的HMACSHA1加密算法(实例)
2017/10/25 PHP
Laravel 5.4.36中session没有保存成功问题的解决
2018/02/19 PHP
laravel 判断查询数据库返回值的例子
2019/10/11 PHP
用javascript来实现动画导航效果的代码
2007/12/16 Javascript
《JavaScript高级程序设计》阅读笔记(二) ECMAScript中的原始类型
2012/02/27 Javascript
js Dialog 实践分享
2012/10/22 Javascript
js判断undefined变量类型使用typeof
2013/06/03 Javascript
jQuery学习之prop和attr的区别示例介绍
2013/11/15 Javascript
js对象内部访问this修饰的成员函数示例
2014/04/27 Javascript
深入理解JavaScript中的箭头函数
2015/07/28 Javascript
JavaScript BASE64算法实现(完美解决中文乱码)
2017/01/10 Javascript
jQuery通过改变input的type属性实现密码显示隐藏切换功能
2017/02/08 Javascript
基于JavaScript实现五子棋游戏
2020/08/26 Javascript
浅谈Vue 数据响应式原理
2018/05/07 Javascript
微信小程序自定义组件传值 页面和组件相互传数据操作示例
2019/05/05 Javascript
详解Vue-Router源码分析路由实现原理
2019/05/15 Javascript
layer弹窗在键盘按回车将反复刷新的实现方法
2019/09/25 Javascript
js闭包和垃圾回收机制示例详解
2021/03/01 Javascript
Python中的super()方法使用简介
2015/08/14 Python
Python3使用requests包抓取并保存网页源码的方法
2016/03/15 Python
使用Python操作excel文件的实例代码
2017/10/15 Python
pytorch使用指定GPU训练的实例
2019/08/19 Python
如何搭建pytorch环境的方法步骤
2020/05/06 Python
纯CSS3实现的8种Loading动画效果
2014/07/05 HTML / CSS
HTML5注册页面示例代码
2014/03/27 HTML / CSS
大学生求职中的自我评价
2013/10/01 职场文书
法学专业毕业生自荐信范文
2013/12/18 职场文书
幼儿园家长会邀请函
2014/01/15 职场文书
九年级体育教学反思
2014/01/23 职场文书
实习计划书范文
2015/01/16 职场文书
行政司机岗位职责
2015/04/10 职场文书
ztree+ajax实现文件树下载功能
2021/05/18 Javascript
html5 录制mp3音频支持采样率和比特率设置
2021/07/15 Javascript
redis 解决库存并发问题实现数量控制
2022/04/08 Redis
六个好看实用的 HTML + CSS 后台登录入口页面
2022/04/28 HTML / CSS