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 相关文章推荐
js最简单的拖拽效果实现代码
Sep 24 Javascript
js判断undefined变量类型使用typeof
Jun 03 Javascript
js 时间函数应用加、减、比较、格式转换的示例代码
Aug 23 Javascript
js+html5绘制图片到canvas的方法
Jun 05 Javascript
jQuery实现悬浮在右上角的网页客服效果代码
Oct 24 Javascript
javascript日期验证之输入日期大于等于当前日期
Dec 13 Javascript
新入门node.js必须要知道的概念(必看篇)
Aug 10 Javascript
详解AngularJS controller调用factory
May 19 Javascript
微信小程序聊天功能的示例代码
Jan 13 Javascript
vue和H5 draggable实现拖拽并替换效果
Jul 29 Javascript
Openlayers学习之加载鹰眼控件
Sep 28 Javascript
nuxt.js写项目时增加错误提示页面操作
Nov 05 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
YII2.0之Activeform表单组件用法实例
2016/01/09 PHP
php表单文件iframe异步上传实例讲解
2017/07/26 PHP
详解PHP 7.4 中数组延展操作符语法知识点
2019/07/19 PHP
javascript面向对象之Javascript 继承
2010/05/04 Javascript
javascript里绝对用的上的字符分割函数总结
2014/07/31 Javascript
jquery实现页面关键词高亮显示的方法
2015/03/12 Javascript
avalonjs制作响应式瀑布流特效
2015/05/06 Javascript
Jquery中attr与prop的区别详解
2017/05/27 jQuery
bootstrap daterangepicker汉化以及扩展功能
2017/06/15 Javascript
layer弹出层 iframe层去掉滚动条的实例代码
2018/08/17 Javascript
脚手架vue-cli工程webpack的作用和特点
2018/09/29 Javascript
微信小程序使用canvas的画图操作示例
2019/01/18 Javascript
微信小程序页面间传值与页面取值操作实例分析
2019/04/30 Javascript
JS script脚本中async和defer区别详解
2020/06/24 Javascript
three.js欧拉角和四元数的使用方法
2020/07/26 Javascript
[49:08]FNATIC vs Infamous 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/18 DOTA
[32:17]完美世界DOTA2联赛循环赛LBZS vs Forest第二场 10月30日
2020/10/31 DOTA
python进阶教程之循环相关函数range、enumerate、zip
2014/08/30 Python
Python中的迭代器漫谈
2015/02/03 Python
python leetcode 字符串相乘实例详解
2018/09/03 Python
Pandas之groupby( )用法笔记小结
2019/07/23 Python
Python实现CNN的多通道输入实例
2020/01/17 Python
python动态文本进度条的实例代码
2020/01/22 Python
CSS3 特效范例整理
2011/08/22 HTML / CSS
如何避免常见的6种HTML5错误用法
2017/11/06 HTML / CSS
美国折扣网站:jClub
2017/08/07 全球购物
欧舒丹加拿大官网:L’Occitane加拿大
2017/10/29 全球购物
Laravel中Kafka的使用详解
2021/03/24 PHP
幼师岗位求职简历的自荐信格式
2013/09/21 职场文书
数控技术与应用毕业生自荐信
2013/09/24 职场文书
班组建设经验交流材料
2014/05/12 职场文书
党的群众路线教育实践活动对照检查材料思想汇报(党员篇)
2014/09/25 职场文书
琅琊山导游词
2015/02/05 职场文书
自主招生推荐信格式模板
2015/03/24 职场文书
党支部鉴定意见
2015/06/02 职场文书
自动在Windows中运行Python脚本并定时触发功能实现
2021/09/04 Python