js实现数组和对象的深浅拷贝


Posted in Javascript onSeptember 30, 2017

前提:原始数据类型和对象类型赋值时的差异

JavaScript的数据类型分为原始数据类型和对象类型。二者在内存中存放的方式不同,导致了其赋值时差异。分别举个栗子

var x = 1;
 var y = x; //y获得了和x同样的值
 y = 2;
 console.log(x); // 1

 var m = [1,2]; //m存放的是指向[1,2]这个数组对象的引用地址
 var n = m; //n也获得 [1,2]数组对象的引用地址
 n[0] = 3;
 console.log(m); //[3,2]

由上栗子可以看出 :原始数据类型赋值时,给的是实实在在的数据值 ,赋值后二者只是值一样而已,不会相互影响; 而对象类型,给的是 原数据的引用地址,所以新旧数据会互相影响,因为本质上还是同一个数据对象,如上栗中的数组 

什么是浅拷贝?

顾名思义,浅拷贝就是流于表面的拷贝方式;当属性值为对象类型时,只拷贝了对象数据的引用,导致新旧数据没有完全分离,还会互相影响。再举个栗子···

//测试数据
var array1 = ['a',1,true,{name:'lei',age:18}];
 
//concat() slice() 实现浅拷贝
var array2 = array1.concat()
 
//修改拷贝后的数据
array2[0] = 'b';      //array1[0]是原始数据类型 所以是直接赋值的
array2[3].name = 'zhang';  //array1[3]是对象数据类型 所以拷贝的是对象的引用,其实还是和原数组使用同一对象
 
console.log(array1);  // ['a',1,true,{name:'zhang',age:18}]

栗子中 array2是array1的浅拷贝对象,数组元素是原始数据类型的不会相互影响了(array1[0]),但是array1[3]是对象类型,还是会互相影响。

如何实现浅拷贝

上栗中的  array.concat()或者array.slice() 是特殊的实现数组浅拷贝的方式。

如何自己实现呢?遍历对象/数组的每个属性,然后赋值给一个新的对象不就行了么,如下实现

//实现浅拷贝
 function shallowCopy( target ){
  if(typeof target !== 'object') return ;
  //判断目标类型,来创建返回值
  var newObj = target instanceof Array ? [] : {};
 
  for(var item in target){
   //只复制元素自身的属性,不复制原型链上的
   if(target.hasOwnProperty(item)){
    newObj[item] = target[item]
   }
  }
 
  return newObj
 }</strong>
 
 //测试
 
 var test = [1,'a',{name:'lei',age:18}];
 
 var copy = shallowCopy(test);
 console.log(copy[2].name);  //lei
 
 copy[2].name = 'zhang';
 console.log(test[2].name);  //zhang  原数据也被修改

深拷贝及其实现

从浅拷贝解释基本可以明白,深拷贝就是 ‘完全'拷贝,拷贝之后新旧数据完全分离,不再共用对象类型的属性值,不会互相影响。

实现方式:

取巧方式 JSON.parse(JSON.stringify(Obj))  

var test = [1,'a',{name:'lei',age:18}]; 
var copy1 = JSON.parse(JSON.stringify(test)); //特殊方式 
console.log(copy1); 
copy1[2].name = 'zhang'
console.log(test);  //[1,'a',{name:'lei',age:18}] 未受到影响

注意:这种方式不能深拷贝有属性值为函数的对象,  可自行尝试

2. 实现深拷贝

    已经实现了浅拷贝,思考下应该是对 对象类型属性值赋值时,导致的没有完全分离,所以要修改下 拷贝对象类型属性值的方式,对它再调用一次深拷贝,这样就实现了深拷贝,如下:

//实现深拷贝
function deepCopy( target ){
 if(typeof target !== 'object') return ;
 //判断目标类型,来创建返回值
 var newObj = target instanceof Array ? [] : {};
 
 for(var item in target){
  //只复制元素自身的属性,不复制原型链上的
  if(target.hasOwnProperty(item)){
   newObj[item] = <strong>typeof target[item] == 'object' ? deepCopy(target[item]) : target[item] //判断属性值类型
</strong>  }
 }
 
 return newObj
}
 
//测试
var test = [1,'a',{name:'lei',age:18}];
 
var copy2 = deepCopy(test);
copy2[2].name = 'zhang'
 
console.log(test); ////[1,'a',{name:'lei',age:18}] 未受到影响

总结

一定要理解造成浅拷贝的原因:对象类型数据复制时,复制了引用地址,用的还是同一个数据对象;所以实现深拷贝的方式就是要对 对象类型属性值递归进行深拷贝,避免直接赋值。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript中的稀疏数组与密集数组[译]
Sep 17 Javascript
js获取元素到文档区域document的(横向、纵向)坐标的两种方法
May 17 Javascript
textarea 控制输入字符字节数(示例代码)
Dec 27 Javascript
Javascript堆排序算法详解
Dec 03 Javascript
JavaScript实现添加、查找、删除元素
Jul 02 Javascript
基于JavaScript实现类似于百度学术高级检索功能
Mar 02 Javascript
JQuery核心函数是什么及使用方法介绍
May 03 Javascript
jquery ezUI 双击行记录弹窗查看明细的实现方法
Jun 01 Javascript
ES6新特征数字、数组、字符串
Oct 01 Javascript
使用JSON作为函数的参数的优缺点
Oct 27 Javascript
mongoose中利用populate处理嵌套的方法
May 26 Javascript
Vue自定义过滤器格式化数字三位加一逗号实现代码
Mar 23 Javascript
node通过express搭建自己的服务器
Sep 30 #Javascript
react-native中ListView组件点击跳转的方法示例
Sep 30 #Javascript
详解在Vue中有条件地使用CSS类
Sep 30 #Javascript
react-native组件中NavigatorIOS和ListView结合使用的方法
Sep 30 #Javascript
vue按需引入element Transfer 穿梭框
Sep 30 #Javascript
vue获取DOM元素并设置属性的两种实现方法
Sep 30 #Javascript
jQuery完成表单验证的实例代码(纯代码)
Sep 30 #jQuery
You might like
建立文件交换功能的脚本(一)
2006/10/09 PHP
Thinkphp模板中使用自定义函数的方法
2012/09/23 PHP
php中AES加密解密的例子小结
2014/02/18 PHP
详解HTTP Cookie状态管理机制
2016/01/14 PHP
php+redis在实际项目中HTTP 500: Internal Server Error故障排除
2017/02/05 PHP
jquery.cvtooltip.js 基于jquery的气泡提示插件
2010/11/19 Javascript
HTML上传控件取消选择
2013/03/06 Javascript
利用JS实现浏览器的title闪烁
2013/07/08 Javascript
动态创建script标签实现跨域资源访问的方法介绍
2014/02/28 Javascript
JS对字符串编码的几种方式使用指南
2015/05/14 Javascript
JavaScript原生编写《飞机大战坦克》游戏完整实例
2017/01/04 Javascript
jQuery图片轮播功能实例代码
2017/01/29 Javascript
springMVC + easyui + $.ajaxFileUpload实现文件上传注意事项
2017/04/23 Javascript
浅谈关于angularJs中使用$.ajax的注意点
2017/08/12 Javascript
jQuery实现的导航条点击后高亮显示功能示例
2019/03/04 jQuery
ant-design-vue中tree增删改的操作方法
2020/11/03 Javascript
详解JavaScript 中的批处理和缓存
2020/11/19 Javascript
[51:26]VP vs VG 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python实现的简单文件传输服务器和客户端
2015/04/08 Python
keras 解决加载lstm+crf模型出错的问题
2020/06/10 Python
Html5移动端div固定到底部实现底部导航条的几种方式
2021/03/09 HTML / CSS
阿里健康大药房:阿里自营网上药店
2017/08/01 全球购物
Bravofly德国:预订廉价航班和酒店
2019/09/22 全球购物
护理专业应届毕业生推荐信
2013/11/15 职场文书
庆六一宣传标语
2014/10/08 职场文书
2014离婚协议书范文(3篇)
2014/11/29 职场文书
2015年办公室工作总结范文
2015/03/31 职场文书
2015年学校安全工作总结
2015/04/22 职场文书
2016年寒假生活小结
2015/10/10 职场文书
出纳2015年度工作总结范文
2015/10/14 职场文书
干货:如何写好观后感 !
2019/05/21 职场文书
导游词之北京明十三陵
2019/10/28 职场文书
SpringDataJPA实体类关系映射配置方式
2021/12/06 Java/Android
Apache Pulsar结合Hudi构建Lakehouse方案分析
2022/03/31 Servers
【DOTA2】高能暴走TK秀!PSG LGD vs ASTER - DPC 2022 WINTER TOUR CN
2022/04/02 DOTA
Springboot集成kafka高级应用实战分享
2022/08/14 Java/Android