js对象分为基本类型和复合(引用)类型,基本类型存放在栈内存,复合(引用)类型存放在堆内存。
js的深浅拷贝只针对复杂数据类型(object,array)的复制问题,深浅拷贝都能实现在已有对象上复制一份的作用,但是对象的实例是存储在堆内存中然后通过一个引用值去操作对象,因此拷贝分两种情况,拷贝引用和拷贝实例,这是深浅拷贝的区别。
。浅拷贝:拷贝引用,拷贝后的引用都是指向同一个对象的实例,彼此之间的操作会相互影响。
。深拷贝:在堆中重新分配内存,并且把原对象的所有属性都进行新建拷贝,拷贝后的对象与原来的对象完全隔离,互不影响。
一。数组的深浅拷贝
<script type="text/javascript"> /*数组的浅拷贝*/ var arr = [1,3,3]; var arrcopy = arr;//把arr赋值给arrcopy arrcopy[1]="copy"; console.log(arr);//[1, "copy", 3] console.log(arrcopy);//[1, "copy", 3] </script>这种是浅拷贝,但是我们想要的是arr的值不会随arrcopy的值的改变而改变对么?这里用到数组的深拷贝解决,常用方法有Array.prototype.slice() Array,prototype.concat() jQuery的$.extend({},obj),以及ES6的两种新的复制方法,不会发生引用,分别是Array.from(要复制的数组) ...(这个方法也可以用在函数的形参上面)。
1.方法一,数组的深拷贝(Array.prototype.slice())
<script type="text/javascript"> /*数组的深拷贝*/ var arr = [1,2,3]; var arrcopy = arr.slice(0); arrcopy[1] = 'copy'; console.log(arr);//[1, 2, 3] console.log(arrcopy);//[1, "copy", 3] </script>2.方法二,数组的深拷贝( Array,prototype.concat() )
<script type="text/javascript"> /*数组的深拷贝---Array,prototype.concat()*/ /*concat() 方法用于连接两个或多个数组,该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。*/ var arr = [1,2,3,4]; var arrcopy = arr.concat(); arrcopy[1] = 'copy'; console.log(arr);//[1, 2, 3, 4] console.log(arrcopy);//[1, "copy", 3, 4] </script>
二。ES6中深拷贝
1.第一种:Array.from(要复制的数组)
<script type="text/javascript"> /*数组深拷贝ES6的两种方法*/ /*第一种:Array.from(要复制的数组)*/ var arr = [1,2,3]; var arrcopy = Array.from(arr); arr.push(4); console.log(arr);//[1, 2, 3, 4] console.log(arrcopy);//[1, 2, 3] arrcopy.push('copy'); console.log(arr);//[1, 2, 3, 4] console.log(arrcopy);//[1, 2, 3, "copy"] </script>
2.第二种:...
<script type="text/javascript"> /*数组深拷贝ES6的两种方法*/ /*第二种:...*/ var arr = [1,2,3,4,5]; var arrcopy = [...arr]; arr.push(6); console.log(arr);//[1, 2, 3, 4, 5, 6] console.log(arrcopy);//[1, 2, 3, 4, 5] arrcopy.push('copy'); console.log(arr);//[1, 2, 3, 4, 5, 6] console.log(arrcopy);//[1, 2, 3, 4, 5, "copy"] </script>
第二种方法...用到函数的形参上
<script type="text/javascript"> /*数组深拷贝ES6的两种方法*/ /*...这个方法也可以用在函数的行参上面。*/ var arr = [1,2,3,5]; function show(...arr) {//直接来复制arguments这个伪数组,让它变成真正的数组,从而拥有数组的方法。 console.log(arr);//[1,2,3,5] arr.push(6); console.log(arr);//[1,2,3,5,6] } show(arr); </script>
三。对象的深浅拷贝
1.对象的浅拷贝
<script type="text/javascript"> //最简单的对象浅拷贝 var a = {c:1}; var b = a; console.log(a === b);//true console.log(b.c)//1 </script>2.对象的深拷贝,常见的方法有:JSON.parse() JSON.stringify() jQuery的$.extend(true,{},obj) 等。
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script type="text/javascript"> /*对象的深拷贝*/ var a = {b:{c:1}}; var d = $.extend(true,{},a); console.log(a===d);//false a.b.c = 3; console.log(d.b.c);//输出1,没有改变 </script>通过循环来复制JSON.stringify()[从一个对象中解析出字符串]
<script type="text/javascript"> /*深拷贝---通过循环来复制*/ var arr = [1,2,3]; var newarr = []; for(var i=0;i<arr.length;i++){ newarr[i]=arr[i]; } arr.push(5); newarr.push('new'); console.log(arr);//[1, 2, 3, 5] console.log(newarr);//[1, 2, 3, "new"] //json var json1 = {"name":"pxq","age":25,"job":"前端开发"}; var json2 = {}; for(var name in json1){ json2[name] = json1[name]; } console.log(JSON.stringify(json1));//{"name":"pxq","age":25,"job":"前端开发"} console.log(JSON.stringify(json2));//{"name":"pxq","age":25,"job":"前端开发"} json1.a = 1; json2.b = 2; console.log(JSON.stringify(json1));//{"name":"pxq","age":25,"job":"前端开发","a":1} console.log(JSON.stringify(json2));//{"name":"pxq","age":25,"job":"前端开发","b":2} </script>深复制,复制一个复杂的对象,可以用 递归 的思想来写,节省性能,不会发生引用。
<script type="text/javascript"> /*而深复制的话,我们要求复制一个复杂的对象,那么我们就可以利用递归的思想来做,及省性能,又不会发生引用。*/ // var json1 = {"arr1":[1,2,3,4],"name":"pxq","age":25}; var json1 = {"arr1":[1,2,3,4]}; var json2 = {}; function copy(obj1,obj2){ //obj1=[1,2,3,4],obj2=[] var obj2 = obj2 || {}; //最初的时候给它一个初始值等于它自己或者一个json for(var name in obj1){ console.log(typeof (obj1[name])); console.log(obj1[name]); if(typeof obj1[name] === "object"){ obj2[name] = (obj1[name].constructor === Array)?[]:{};//赋值obj2={arr1:[]} copy(obj1[name],obj2[name]); console.log(obj2[name]); }else{ obj2[name]=obj1[name];//string类型不是对象,直接等于即可,不会发生引用 } } return obj2;//[1,2,3,4] } json2 = copy(json1,json2);//[1,2,3,4] json1.arr1.push(666); console.log(json1.arr1);//[1, 2, 3, 4, 666] console.log(json2.arr1);//[1, 2, 3, 4] </script>