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 相关文章推荐
采用call方式实现js继承
May 20 Javascript
Javascript类型转换的规则实例解析
Feb 23 Javascript
实现JavaScript高性能的数据存储
Dec 11 Javascript
微信小程序中使用Promise进行异步流程处理的实例详解
Aug 17 Javascript
Node.js 使用递归实现遍历文件夹中所有文件
Sep 18 Javascript
node通过express搭建自己的服务器
Sep 30 Javascript
jQuery实现碰到边缘反弹的动画效果
Feb 24 jQuery
jQuery实现table表格checkbox全选的方法分析
Jul 04 jQuery
微信小程序动态增加按钮组件
Sep 14 Javascript
vue-vuex中使用commit提交mutation来修改state的方法详解
Sep 16 Javascript
深入理解基于vue-cli的webpack打包优化实践及探索
Oct 14 Javascript
原生javascript运动函数的封装示例【匀速、抛物线、多属性的运动等】
Feb 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
DC四月将推出百页特刊漫画 纪念小丑诞生80周年
2020/04/09 欧美动漫
博士208HAF收音机实习报告
2021/03/02 无线电
php更新mysql后获取影响的行数发生异常解决方法
2013/03/28 PHP
PHP+Mysql基于事务处理实现转账功能的方法
2015/07/08 PHP
laravel 如何实现引入自己的函数或类库
2019/10/15 PHP
laravel框架中路由设置,路由参数和路由命名实例分析
2019/11/23 PHP
深入理解Javascript闭包 新手版
2010/12/28 Javascript
非常强大的 jQuery.AsyncBox 弹出对话框插件
2011/08/29 Javascript
javascript 获取元素样式必杀技
2014/05/04 Javascript
实例讲解js验证表单项是否为空的方法
2016/01/09 Javascript
JavaScript禁止用户多次提交的两种方法
2016/07/24 Javascript
Angular使用ng-messages与PHP进行表单数据验证
2016/12/28 Javascript
javascript工厂模式和构造函数模式创建对象方法解析
2016/12/30 Javascript
微信小程序开发之入门实例教程篇
2017/03/07 Javascript
微信小程序城市定位的实现实例(获取当前所在国家城市信息)
2017/05/17 Javascript
全面介绍vue 全家桶和项目实例
2017/12/27 Javascript
解决vue项目中type=”file“ change事件只执行一次的问题
2018/05/16 Javascript
一个简单的node.js界面实现方法
2018/06/01 Javascript
详解为生产环境编译Angular2应用的方法
2018/12/10 Javascript
详解vue引入子组件方法
2019/02/12 Javascript
写一个Vue Popup组件
2019/02/25 Javascript
Node.js在图片模板上生成二维码图片并附带底部文字说明实现详解
2019/08/07 Javascript
Vue 通过公共字段,拼接两个对象数组的实例
2019/11/07 Javascript
详解vue或uni-app的跨域问题解决方案
2020/02/21 Javascript
vue添加锚点,实现滚动页面时锚点添加相应的class操作
2020/08/10 Javascript
js通过canvas生成图片缩略图
2020/10/02 Javascript
详解Vue的mixin策略
2020/11/19 Vue.js
[02:52]DOTA2新手基础教程 米波
2014/01/21 DOTA
Python标准库之多进程(multiprocessing包)介绍
2014/11/25 Python
python实现的守护进程(Daemon)用法实例
2015/06/02 Python
记一次Django响应超慢的解决过程
2020/09/17 Python
关于PySnooper 永远不要使用print进行调试的问题
2021/03/04 Python
应届生人事助理求职信
2013/11/09 职场文书
新闻专业毕业生英文求职信
2014/03/19 职场文书
党员个人年度总结
2015/02/14 职场文书
煤矿安全学习心得体会
2016/01/18 职场文书