javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())
javascript 数组和对象的浅度复制和深度复制
在平常我们用 ‘=’来用一个变量引用一个数组或对象,这里是‘引用’而不是复制下面我们看一个例子引用和复制是什么概念
var arr=[1,2,3,'f',2,'s',1];
var cloneArr=arr; //这时cloneArr确实是[1,2,3,'f',2,'s',1]
//我们来打印看一下
console.log(cloneArr); //我们来打印一下看看 [1,2,3,'f',2,'s',1]
console.log(arr); //这个也一样 [1,2,3,'f',2,'s',1] //打印结果
[1,2,3,"f",2,"s",1]
[1,2,3,"f",2,"s",1]
但是当我们改变一个数组元素时,我们看一下会发生什么
arr[0]='小明';
console.log('arr:'+arr); //这个打印是 ["小明", 2, 3, "f", 2, "s", 1] 没有任何问题
console.log('cloneArr:'+cloneArr); //我们打印一下cloneArr 发现也变了 ["小明", 2, 3, "f", 2, "s", 1] //我们在试试改变cloneArr,看看会发生什么 cloneArr.push('我是cloneArr');
console.log('arr:'+arr); //["小明", 2, 3, "f", 2, "s", 1, "我是cloneArr"]
console.log('cloneArr:'+cloneArr); //这个也变了 ["小明", 2, 3, "f", 2, "s", 1, "我是cloneArr"] //打印结果
arr:小明,2,3,f,2,s,1
cloneArr:小明,2,3,f,2,s,1
arr:小明,2,3,f,2,s,1,我是cloneArr
cloneArr:小明,2,3,f,2,s,1,我是cloneArr
对象也是一个道理我们来看一个例子
var obj={
name:'小明',
age:18,
tel:'13108123123',
sex:'男'
};
cloneObj=obj;
cloneObj['name']='小红';
console.log(obj); // {name: "小红", age: 18, tel: "13108123123", sex: "男"}
//打印结果:
Object {name:"小红", age: 18, tel:"13108123123", sex: "男"}
在开发中一般不想有这种情况发生我们就用到了复制这个功能下面我们来介绍一下都有哪些复制,深度复制和浅复制有什么区别
一、数组的深浅复制
1.我们先来看一下数组浅复制的一些方法 slice concat 浅复制没有函数时for循环遍历就不说了这样多此一举,
一般情况下数组浅复制可以用slice和concat解决,我们看一下例子
var arr=[1,2,3,'f',2,'s',1];
var cloneArr1=arr.slice();
var cloneArr2=arr.concat();
console.log('未更改前:'+'\n'+arr+'\n'+cloneArr1+'\n'+cloneArr2); //是一样的 //为了方便看出来这里每个更改不同元素
arr[0]='我是arr的第一项';
cloneArr1[1]='我是cloneArr1的第二项';
cloneArr2.push('我是cloneArr新添加'); //我们在打印一下看看
console.log('更改后:'+'\n'+arr+'\n'+cloneArr1+'\n'+cloneArr2); //打印结果
更改前:
1,2,3,f,2,s,1
1,2,3,f,2,s,1
1,2,3,f,2,s,1
更改后:
我是arr的第一项,2,3,f,2,s,1
1,我是cloneArr1的第二项,3,f,2,s,1
1,2,3,f,2,s,1,我是cloneArr新添加
从上面例子可以看出当我们把数组截取或拼接后返回的新数组就和原数组就不是引用关系了,而是一个新的独立的数组,具体可以看Array中 slice 和 concat 的介绍 https://blog.csdn.net/xiaoxiaoshuai__/article/details/77840759
上面看似轻松完成了浅复制,
那我们建一个二维数组看一下浅复制还能完成任务吗
我们在看看这个例子
var arr2=[1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
var cloneArr1=arr2.slice();
var cloneArr2=arr2.concat();
console.log(arr2); //是一样的
console.log(cloneArr1); //是一样的
console.log(cloneArr2); //是一样的
//我们在这里给该元素试一下
arr2[0]=101;
console.log(arr2); //更改了 [101,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr1); //没变 [1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr2); //没变 [1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
//看似没有什么问题,我们在试一下更改一下二级数组里面的元素
arr2[7][2]='eee000';
console.log(arr2); //更改了 [101,2,3,4,5,6,7,['q','w','eee000','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr1); //这个怎么也更改了? [1,2,3,4,5,6,7,['q','w','eee000','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr2); //这个怎么也更改了? [1,2,3,4,5,6,7,['q','w','eee000','w'],8,{name:'小明',age:18},9,7,54];
这时发现二级数组用这些方法好像也不行,
那我们来试一下JSON.parse(JSON.stringify())方法解决一下;
var arr3=[1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
var cloneArr1=JSON.parse(JSON.stringify(arr3));
console.log(arr3); //[1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
console.log(cloneArr1); //成功复制过来了 [1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
//那我们改变一下值看一下
arr3[0]=101;
arr3[7][1]='qqqpppqqpp';
arr3[9]['name']='飞上天';
console.log(arr3); //[101,2,3,4,5,6,7,['q','qqqpppqqpp','e','w'],8,{name:'飞上天',age:18},9,7,54];
console.log(cloneArr1); //这样好像可以 [1,2,3,4,5,6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54];
用JSON.parse(JSON.stringify())好像万事大吉了,复制解决了,我们再让数据复杂一下看看
function fn1(age){
alert(age);
}
var b="bbb";
var arr3=[6,7,['q','w','e','w'],8,{name:'小明',age:18,fn:function(name){alert(name);}},9,7,54,fn1,b];
var cloneArr1=JSON.parse(JSON.stringify(arr3))
console.log(arr3); //[,6,7,['q','w','e','w'],8,{name:'小明',age:18,fn:function(name){alert(name);}},9,7,54,function function,'bbb'];
console.log(cloneArr1); //[6,7,['q','w','e','w'],8,{name:'小明',age:18},9,7,54,null,'bbb'];这是发现fn函数和函数名没有被复制上
我们发现JSON.parse(JSON.stringify())不能复制带有函数的数组,这要怎么办呢
我们先来看一下对象的复制,后面一起说
二、对象的深浅复制
我们先来看一下数组浅复制的一些方法 assign
function fn2(age){
alert(age);
}
var obj={
name:'小明',
age:18,
tel:'13108123123',
sex:'男',
fn:function(name){
console.log(name)
},
fn2:fn2
};
cloneObj=Object.assign({},obj);
console.log(obj);
console.log(cloneObj); //这里成功复制了
//我们改变一下试试
obj['name']='小红';
console.log(obj); //改变了
console.log(cloneObj); //没改变
这样复制成功了,正常的对象是可以了,我们要是再是一下复杂一点的试试
function fn2(age){
alert(age);
}
var obj={
name:'小明',
age:18,
tel:'13108123123',
sex:'男',
fn:function(name){
console.log(name)
},
fn2:fn2,
obj2:{
name:'小红',
age:16
},
li:[12,23,45,23]
};
cloneObj=Object.assign({},obj);
console.log(obj);
console.log(cloneObj); //这里成功复制了
//我们改变一下试试
obj['name']='小红红';
obj['obj2']['name']='小明明';
obj['li'][1]=900;
console.log(obj); //改变了
console.log(cloneObj); // obj中的name没有改变,但是obj2中的name和obj中li中的值都变了
复杂了之后好像Object.assign不能完成任务了,
那我们在用JSON.parse(JSON.stringify()),试一下看看能问题吗
cloneObj=JSON.parse(JSON.stringify(obj));
console.log(obj);
console.log(cloneObj); //这里成功复制了 //我们改变一下试试 obj['name']='小红红';
obj['obj2']['name']='小明明';
obj['li'][1]=900;
console.log(obj);
console.log(cloneObj); // 从打印结果来看,除了函数之外其他的都可以深度拷贝
好像可以的,但是我们还记得吗JSON.parse(JSON.stringify())不能copy 函数及函数变量
综上所述:
数组浅复制:slice 、concat
数组深复制:JSON.parse(JSON.stringify(arr)); 不可以解决数组中带有函数和函数变量
对象浅复制:Object.assign({},obj)
对象深复制:JSON.parse(JSON.stringify(arr)); 不可以解决对象中带有函数和函数变量
那我们来研究一下又是多层对象或数组又有函数怎么解决呢
好吧,百度没有查到,自己封装了一个方法来实现吧
function fn2(age){
alert(age);
}
var obj={
name:'小明',
age:18,
tel:'13108123123',
sex:'男',
fn:function(name,a,b){
this.name=name;
this.fnn=function(a,b){
console.log(a+b)
}
},
fn2:fn2,
obj2:{
name:null,
sex:'男',
age:15
},
li:[1,null,0,23],
lii:[1,2,3,4,45,[1,2,3,43,3,{name:'111',age:'1',e:[2,3,4,1,1,2],fnnc:function(){console.log(11);}}],3,2,]
};
//我们来看一下复制的用时 平均 0.4~0.9 ms之前
console.time();
var cloneObj2=clone(obj); //clone为自定义函数这里买个关子@~@
console.timeEnd();
obj['name']='小红红红话';
obj['obj2']['name']='大红花那个大红花';
obj['lii'][5][1]='5656565';
obj['lii'][5][5]['name']='大红袍';
console.log(obj); //都改变了
console.log(cloneObj2); //都没变,ok可以
//我们在看看复制的函数的情况
cloneObj2['fn2'](16); //正常弹出16
根据模拟数据测试可以通过以上的问题深度复制应该不成问题,源码在下面,代码行数有点多,截图字偏小有兴趣的可以在Git上下载看源码:https://github.com/liushuai541013304/oject-deep-clone
不想下载的可以直接在下方留言即可,楼主会乖乖奉上@~@。

javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())的更多相关文章
- javascript 数组以及对象的深拷贝(复制数组或复制对象)的方法
前言 for,slice(0),concact() 在js中,数组和对象的复制如果使用=号来进行复制,那只是浅拷贝.如下图演示: 如上,arr的修改,会影响arr2的值,这显然在绝大多数情况下,并不 ...
- JavaScript 数组(Array)对象的方法
JavaScript 数组(Array)对象的方法 concat() 描述:用于连接两个或多个数组.该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. 原型:arrayObject.conc ...
- javascript 数组以及对象的深拷贝
如果 let arr2 = arr1: 那么只是赋值的引用,改变arr2也会相应的改变arr1: 如果 let arr2 = [].concat(arr1): 如果arr1里面不是引用类型,那么ar ...
- [No0000B9]C# 类型基础 值类型和引用类型 及其 对象复制 浅度复制vs深度复制 深入研究2
接上[No0000B5]C# 类型基础 值类型和引用类型 及其 对象判等 深入研究1 对象复制 有的时候,创建一个对象可能会非常耗时,比如对象需要从远程数据库中获取数据来填充,又或者创建对象需要读取硬 ...
- 使用JSON.parse(),JSON.stringify()实现对对象的深拷贝
根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字符串会新辟一个新的存储地址,这样就切断了引用对象的指针联系. 测试例子: var test={ a:"ss", ...
- JSON.parse(JSON.stringify()) 实现对对象的深度拷贝,从而互不影响
JSON.parse(JSON.stringify({"key": "value"})) 根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字 ...
- DataTable复制数据,深度复制
/**/ /// <summary> /// 复制数据,深度复制 /// </summary> /// <param name="dataSourceRow&q ...
- JSON.parse(JSON.stringify()) 实现对对象的深拷贝
JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...
- javascript数组、对象和Null的typeof同为object,区分解决办法
在JS里typeof 大家用的很多,可以使对于数组.对象和Null无法区分的问题,看了看犀牛书还是有解决办法的. document.writeln(typeof "abc"); / ...
随机推荐
- YARN构建--解决cypress下载慢问题
背景 注意: 此方案仅适合已经自行搭建私有仓库的用户使用 如非必要,尽可能使用软件开发云或其他服务提供的镜像站,避免此类特殊处理(会导致仓库维护成本增加) 场景描述 YARN构 ...
- bzoj 1415: [Noi2005]聪聪和可可 期望dp+记忆化搜索
期望dp水题~ 你发现每一次肯定是贪心走 2 步,(只走一步的话就可能出现环) 然后令 $f[i][j]$ 表示聪在 $i$,可在 $j$,且聪先手两个人碰上面的期望最小次数. 用记忆化搜索转移就行了 ...
- Gluon学习02-使用GPU
小书匠kindle 目录,方便快速定位: 1.安装cuda与cudnn 2.安装mxnet-gpu 本机环境介绍: 系统:Linuxmint Python版本:Python3 1.安装cuda与cud ...
- 开源是个巨大的坑,谁来帮帮我 - smartmontools 虐我记
最近在试用smartmontools,感觉还行,于是乎想找来源码改改试试,这下可好,掉坑里了.呜呜呜... smartmontools的源码在这里可以看到:https://www.smartmonto ...
- puppteer的使用
官方文档:Puppeteer 今天大概介绍一下我项目用到的puppeteer操作: // 启动浏览器 const browser = await puppeteer.launch({ executab ...
- cas系列-自定义异常提示(五)
cas对于异常提示可以支持多语言,默认是英语,具体文件格式大同小异.这里以cas5.x版本为例. 官方推荐使用overlay方式部署,这样你只需要关注你自定义的配置即可. 获取自定义配置文件方式: 执 ...
- centos6下安装docker
安装docker对内核版本的要求很高,需要内核3.10以上. 一.docker卸载 查看内核版本: 如果不升级内核到3.10安装docker,后面会有很多奇怪的问题,像我就是拉取不到镜像. 以下我是r ...
- Code First 迁移----官方 应用程序启动时自动升级(MigrateDatabaseToLatestVersion 初始值设定项)
Code First 迁移 如果使用的是 Code First 工作流,推荐使用 Code First 迁移改进应用程序的数据库架构. 迁移提供一组允许以下操作的工具: 创建可用于 EF 模型的初始数 ...
- presto计算日期间隔天数或者小时间隔——date_diff函数使用
“Presto是Facebook最新研发的数据查询引擎,可对250PB以上的数据进行快速地交互式分析.据称该引擎的性能是 Hive 的 10 倍以上.”,亲身用过之后,觉得比hive快了10倍不止. ...
- [Java]两个将秒数转化为日时分秒形式的函数
比如900秒要反应一下,说15分就直观了.下面两个函数性能差不多,大家任意取用. 代码: import java.util.concurrent.TimeUnit; public class Test ...