javascript 数组和对象的浅度复制和深度复制
在日常咱们用 ‘=’来用一个变量引用一个数组或对象,这里是‘引用’而不是复制下面咱们看一个例子引用和复制是什么概念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]
可是当咱们改变一个数组元素时,咱们看一下会发生什么java
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
对象也是一个道理咱们来看一个例子git
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: "男"}
在开发中通常不想有这种状况发生咱们就用到了复制这个功能下面咱们来介绍一下都有哪些复制,深度复制和浅复制有什么区别github
1、数组的深浅复制
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())方法解决一下;this
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())好像万事大吉了,复制解决了,咱们再让数据复杂一下看看spa
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())不能复制带有函数的数组,这要怎么办呢.net
咱们先来看一下对象的复制,后面一块儿说
2、对象的深浅复制
咱们先来看一下数组浅复制的一些方法 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
不想下载的能够直接在下方留言便可,楼主会乖乖奉上@~@。