说到深拷贝和浅拷贝,相信熟悉C和Java的同学们经常涉及到这两个概念
现在以JavaScript为例,讨论深拷贝和浅拷贝
首先这里给大家写一段代码,大家思考,每个代码块的打印的结果应该是什么:
var a=1,b; b=a; b++; console.log("a,"+a); console.log("b,"+b); / var c=[1,2,3],d; d=c; d.splice(0,1); console.log("c,"+c); console.log("d,"+d); / var e={ name:"Jill", age:20 },f; f=e; f.name="Donny"; f.age=32; console.log("e,"+angular.toJson(e,true)); console.log("f,"+angular.toJson(f,true));
首先在第一块代码中,a的打印结果是1,b的打印结果是2
在第二块代码中,c和d的打印结果都是[2,3]
在第三块代码中,e和f的打印结果都是{name:Donny,age:32}
这里大家思考一个问题,为什么当a和b都是基本数据类型时,把a的值赋给b,并修改b的值,a的值却不变
而当c与d为数组类型时,把c的值赋给d,并操作d删除掉数组第一项时,c的值也一并被修改了
同理e与f为对象类型时,把e的值赋给f,修改e的值,f的值也一并被改掉了。其中的原理又是怎么样的
这里像a和b这种,其中一个变量的值赋给另一个变量,并修改另一个变量的值,不会影响前一个变量的情况就是深拷贝
如果我们把前一个变量的值赋给另一个变量,修改后者的值,同时一起影响了前者的值,这种就是浅拷贝
深拷贝由于不引用同一块内存地址,所以改变其中一个的值,并不会影响另一个,但是如果使用浅拷贝,虽然变量名称不同
但是引用的却是同一块内存地址,其中一个变量修改了这个内存地址中的值,另一个变量再次访问这块内存地址时,得到的也是修改后的值
Javascript中基本数据类型变量的相互赋值是使用深拷贝执行的,而像数组和对象这种复杂数据类型,使用的则是浅拷贝
项目开发中我们经常会用到多个controller之间传递数组或者对象,有时也会把数组或者对象类型的数据保存再service中供随时使用
这个时候如果使用浅拷贝会一并修改我们的数据源中的值,会导致数据异常,所以到底是使用深拷贝还是浅拷贝,大家要结合具体需求来判断
用Javascript实现深拷贝代码示例如下:
复制数组:
之前看过一篇文章讨论不同浏览器对不同方法复制数组支持速度的异同,最后的结论是建议使用concat()方法复制数组
var a=[1,2,3]; var b=a.concat();
对象的复制:
var a={ name:"Jill", age:20 }; var b={ name:"", age:"" };
b.name=a.name;
b.age=a.age;
大家从以上代码可以看出,数组的深拷贝比较简单,用concat()方法就可以,但是对象的深拷贝却要知道有哪些固定字段,
定义好对象后,还要一个字段一个字段的赋值,很麻烦,对不对
经常使用angularJS开发项目的我们,往往忽视了angularJS封装好的一系列方法,比如angular.isString(),angular.isNumber(),angular.isArray(),angular.isFunction()来判断各种类型,还在使用JS的typeof和instanceof的同学们一定要意识到这点
在这些angular封装好的方法中,其中有一个叫做angular.copy()的,它是用来实现深拷贝的一个方法,可以直接用这个方法深拷贝
对象,数组,undefined,null等类型,很强大,从此告别复制对象类型数组时的种种复杂
代码示例:
var a=[1,2,3]; var b=angular.copy(a); var c={ name:"Jill", age:20 }; var d=angular.copy(c);
深拷贝之后,我们随意操作赋值后变量的值
深拷贝和浅拷贝不仅仅是JS这门语言中用到,用的不好,往浅了说影响项目开发,往深了说是不了解数据结构
所以弄懂深拷贝和浅拷贝的概念以及如何应用是非常重要的