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 相关文章推荐
Array的push与unshift方法性能比较分析
Mar 05 Javascript
基于JQuery的Select选择框的华丽变身
Aug 23 Javascript
JS Jquery 遍历,筛选页面元素 自动完成(实现代码)
Jul 08 Javascript
js去除空格的12种实用方法
Nov 08 Javascript
解析js如何获取css样式
Dec 11 Javascript
JavaScript实现同一个页面打开多张图片
Dec 29 Javascript
微信小程序实现带刻度尺滑块功能
Mar 29 Javascript
jQuery取得元素标签名称小结(附代码)
Aug 16 jQuery
Nuxt.js开启SSR渲染的教程详解
Nov 30 Javascript
微信小程序如何获取群聊的openGid以及名称详解
Jul 17 Javascript
在Uni中使用Vue的EventBus总线机制操作
Jul 31 Javascript
nuxt.js添加环境变量,区分项目打包环境操作
Nov 06 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
PHP iconv 函数转gb2312的bug解决方法
2009/10/11 PHP
php读取csv实现csv文件下载功能
2013/12/18 PHP
PHP类继承 extends使用介绍
2014/01/14 PHP
PHP简单操作MongoDB的方法(安装及增删改查)
2016/05/26 PHP
Ubuntu 16.04下安装PHP 7过程详解
2017/03/28 PHP
Mootools 1.2教程 Fx.Tween的使用
2009/09/15 Javascript
基于jQuery替换table中的内容并显示进度条的代码
2011/08/02 Javascript
JS 各种网页尺寸判断实例方法
2013/04/18 Javascript
原生js实现改变随意改变div属性style的名称和值的结果
2013/09/26 Javascript
jQuery 自定义下拉框(DropDown)附源码下载
2016/07/22 Javascript
微信小程序 获取微信OpenId详解及实例代码
2016/10/31 Javascript
Nodejs中解决cluster模块的多进程如何共享数据问题
2016/11/10 NodeJs
Vue.js tab实现选项卡切换
2017/05/16 Javascript
JS中将多个逗号替换为一个逗号的实现代码
2017/06/23 Javascript
Django与Vue语法的冲突问题完美解决方法
2017/12/14 Javascript
Webpack打包字体font-awesome的方法示例
2018/04/26 Javascript
JS实现键值对遍历json数组功能示例
2018/05/30 Javascript
Vue.js中的组件系统
2019/05/30 Javascript
layer关闭当前窗口页面以及确认取消按钮的方法
2019/09/09 Javascript
微信小程序 bindtap 传参的实例代码
2020/02/21 Javascript
vue实现商品列表的添加删除实例讲解
2020/05/14 Javascript
python实现数据预处理之填充缺失值的示例
2017/12/22 Python
python之信息加密题目详解
2019/06/26 Python
Python实现列表中非负数保留,负数转化为指定的数值方式
2020/06/04 Python
Python flask框架端口失效解决方案
2020/06/04 Python
database面试题
2013/03/28 面试题
统计岗位职责
2014/02/21 职场文书
说明书范文
2014/05/07 职场文书
运动会广播稿诗歌版
2014/09/12 职场文书
银行资信证明
2015/06/17 职场文书
三八节活动简报
2015/07/20 职场文书
2016年第16个全民国防教育日宣传活动总结
2016/04/05 职场文书
微信小程序和php的登录实现
2021/04/01 PHP
oracle DGMGRL ORA-16603报错的解决方法(DG Broker)
2021/04/06 Oracle
利用 JavaScript 构建命令行应用
2021/11/17 Javascript
Redis+Lua脚本实现计数器接口防刷功能(升级版)
2022/02/12 Redis