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编程起步(第五课)
Jan 10 Javascript
基于逻辑运算的简单权限系统(实现) JS 版
Mar 24 Javascript
js,jQuery 排序的实现代码,网页标签排序的实现,标签排序
Apr 27 Javascript
jQuery之尺寸调整组件的深入解析
Jun 19 Javascript
jquery动态加载select下拉框示例代码
Dec 10 Javascript
深入理解jQuery中的事件冒泡
May 24 Javascript
JS中mouseover和mouseout多次触发问题如何解决
Jun 06 Javascript
JS实现间歇滚动的运动效果实例
Dec 22 Javascript
兼容浏览器的js事件绑定函数(详解)
May 09 Javascript
vue.js前后端数据交互之提交数据操作详解
Apr 24 Javascript
vue项目中添加单元测试的方法
Jul 21 Javascript
jQuery实现数字自动增加或者减少的动画效果示例
Dec 11 jQuery
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
PHP中file_exists()判断中文文件名无效的解决方法
2014/11/12 PHP
php+ajax 实现输入读取数据库显示匹配信息
2015/10/08 PHP
php遍历、读取文件夹中图片并分页显示图片的方法
2016/11/15 PHP
JavaScript 学习笔记(十一)
2010/01/19 Javascript
精通Javascript系列之数值计算
2011/06/07 Javascript
JavaScript高级程序设计 阅读笔记(十七) js事件
2012/08/14 Javascript
利用ajaxfileupload插件实现文件上传无刷新的具体方法
2013/06/08 Javascript
用jquery实现的一个超级简单的下拉菜单
2014/05/18 Javascript
Java File类的常用方法总结
2015/03/18 Javascript
大型JavaScript应用程序架构设计模式
2016/06/29 Javascript
基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解
2016/07/18 Javascript
浅析BootStrap Treeview的简单使用
2016/10/12 Javascript
Mac系统下Webstorm快捷键整理大全
2017/05/28 Javascript
Node.js使用orm2进行update操作时关联字段无法修改的解决方法
2017/06/13 Javascript
jQuery实现右侧抽屉式在线客服功能
2017/12/25 jQuery
使用proxy实现一个更优雅的vue【推荐】
2018/06/19 Javascript
JavaScript读写二进制数据的方法详解
2018/09/09 Javascript
easyUI使用分页过滤器对数据进行分页操作实例分析
2020/06/01 Javascript
微信小程序自定义支持图片的弹窗
2020/12/21 Javascript
Python常用的日期时间处理方法示例
2015/02/08 Python
简单谈谈Python中的几种常见的数据类型
2017/02/10 Python
解决uWSGI的编码问题详解
2017/03/24 Python
在django中使用自定义标签实现分页功能
2017/07/04 Python
Python标准库笔记struct模块的使用
2018/02/22 Python
python使用Matplotlib画条形图
2020/03/25 Python
python 使用xlsxwriter循环向excel中插入数据和图片的操作
2021/01/01 Python
CSS3 简写animation
2012/05/10 HTML / CSS
德国骆驼商店:ActiveFashionWorld
2017/11/18 全球购物
TripAdvisor斯洛伐克:阅读评论、比较价格和酒店预订
2018/04/25 全球购物
澳大利亚网上买书:Angus & Robertson
2019/07/21 全球购物
恶搞卫生巾广告词
2014/03/18 职场文书
文员试用期转正自我鉴定
2014/09/14 职场文书
药品开票员岗位职责
2015/04/15 职场文书
学校运动会加油词
2015/07/18 职场文书
开学随笔
2015/08/15 职场文书
党员干部学习三严三实心得体会
2016/01/05 职场文书