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 相关文章推荐
jqTransform form表单美化插件使用方法
Jul 05 Javascript
cookie 最近浏览记录(中文escape转码)具体实现
Jun 08 Javascript
Jquery创建层显示标题和内容且随鼠标移动而移动
Jan 26 Javascript
Javascript基础教程之变量
Jan 18 Javascript
jQuery插件jFade实现鼠标经过的图片高亮其它变暗
Mar 14 Javascript
jQuery简单实现页面元素置顶时悬浮效果示例
Aug 01 Javascript
JavaScript实现类似拉勾网的鼠标移入移出效果
Oct 27 Javascript
laydate.js日期时间选择插件
Jan 04 Javascript
Angularjs中使用轮播图指令swiper
May 30 Javascript
使vue实现jQuery调用的两种方法
May 12 jQuery
vue 解决文本框被键盘遮住的问题
Nov 06 Javascript
Vue+TypeScript中处理computed方式
Apr 02 Vue.js
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中通过加号合并数组的一个简单方法分享
2011/01/27 PHP
php中数组首字符过滤功能代码
2012/07/31 PHP
php基础教程
2015/08/26 PHP
Yii2框架使用计划任务的方法
2016/05/25 PHP
使用 JScript 创建 .exe 或 .dll 文件的方法
2011/07/13 Javascript
Extjs grid添加一个图片状态或者按钮的方法
2014/04/03 Javascript
js实现图片旋转的三种方法
2014/04/10 Javascript
javascript面向对象之this关键词用法分析
2015/01/13 Javascript
jQuery使用$.each遍历json数组的简单实现方法
2016/04/18 Javascript
JavaScript 基础函数_深入剖析变量和作用域
2016/05/18 Javascript
Bootstrap框架实现广告轮播效果
2016/11/28 Javascript
详解用webpack2.0构建vue2.0超详细精简版
2017/04/05 Javascript
nodejs实现爬取网站图片功能
2017/12/14 NodeJs
浅析vue给不同环境配置不同打包命令
2018/08/17 Javascript
vue组件入门知识全梳理
2020/09/21 Javascript
[01:32]DOTA2上海特锦赛现场采访:最想COS的英雄
2016/03/25 DOTA
[01:47]2018年度DOTA2最具人气解说-完美盛典
2018/12/16 DOTA
Python网络编程基于多线程实现多用户全双工聊天功能示例
2018/04/10 Python
pyinstaller打包单个exe后无法执行错误的解决方法
2019/06/21 Python
Python批量查询关键词微信指数实例方法
2019/06/27 Python
django 使用 PIL 压缩图片的例子
2019/08/16 Python
Python学习工具jupyter notebook安装及用法解析
2020/10/23 Python
详解Python中的GIL(全局解释器锁)详解及解决GIL的几种方案
2021/01/29 Python
加拿大领先的时尚和体育零售商:Sporting Life
2019/12/15 全球购物
介绍一下#error预处理
2015/09/25 面试题
外企财务年会演讲稿
2014/01/03 职场文书
感恩节红领巾广播稿
2014/02/11 职场文书
创建文明学校实施方案
2014/03/11 职场文书
学生会竞选演讲稿怎么写
2014/08/26 职场文书
实习生工作证明范本
2014/09/14 职场文书
生产工厂门卫岗位职责
2014/09/26 职场文书
中学生综合素质自我评价
2015/03/06 职场文书
汽车质检员岗位职责
2015/04/08 职场文书
给女朋友的道歉短信
2015/05/12 职场文书
关于食品安全的演讲稿范文(三篇)
2019/10/21 职场文书
Oracle中update和select 关联操作
2022/01/18 Oracle