经常看到讨论c#深拷贝,浅拷贝的博客,最近js写的比较多, 所以也来玩玩js的对象拷贝。
下面是维基百科对深浅拷贝的解释:
浅拷贝
One method of copying an object is the shallow copy. In the process of shallow copying A, B will copy all of A's field values. If the field value is a memory address it copies the memory address, and if the field value is a primitive type it copies the value of the primitive type.
The disadvantage is if you modify the memory address that one of B's fields point to, you are also modifying what A's fields point to.
一种拷贝对象的方式是浅拷贝,浅拷贝对象A时,对象B将拷贝A的所有字段,如果字段是内存地址,B将拷贝地址,若果字段是基元类型,B将复制其值。
浅拷贝的缺点是如果你改变了对象B所指向的内存地址,你同时也改变了对象A指向这个地址的字段。
深拷贝
An alternative is a deep copy. Here the data is actually copied over. The result is different from the result a shallow copy gives. The advantage is that A and B do not depend on each other but at the cost of a slower and more expensive copy.
另一种是深拷贝,这种方式会完全拷贝所有数据,优点是B与A不会相互依赖(A,B完全脱离关联), 缺点是拷贝的速度更慢,代价更大 (我的理解是耗费了更多内存空间)
C#中的对象拷贝
c#中的浅拷贝
C#万恶的Object基类中定义了一个protected的浅拷贝函数MemberwiseClone ,下面是测试代码
public class Address { public string ZipCode { get; set; } public string City { get; set; } } public class Person { public string Name { get; set; } public int Age { get; set; } public Address Address { get; set; } /// <summary> /// 暴露浅拷贝功能 /// </summary> /// <returns></returns> public Person Clone() { return this.MemberwiseClone() as Person; } } class Program { static void Main(string[] args) { Person p = new Person(); p.Name = "leon"; p.Age = 5; p.Address = new Address { ZipCode = "200000", City = "Shanghai" }; Person copy = p.Clone(); copy.Address.City = "beijing"; Console.WriteLine(p.Address.City); // print beijing Console.Read(); } }
c#中的深拷贝
我们可以利用序列化和反序列化来轻易实现深拷贝,c#中可选的序列化方法有许多,比如BinaryFormatter, XML serializer, JSON serializer ,因为本文主要是将js的,所以不过多介绍。
javascript 也来玩玩拷贝
javascript 浅拷贝对象
这里把上面的c# person对象 翻译成一个json 对象 {name:'leon', age:5, address:{zipcode:'200000',city:'shanghai'}}
在js中, 浅拷贝非一般的简单,如下,大家可以测试测试 (为了简单,这里省去了参数的判断) :
function shallowCopy( o ) { var copy = {}; for ( var i in o ) { copy[i] = o[i]; } return copy; }
javascript 深拷贝对象
要实现js的深拷贝也很简单, 就是在浅拷贝的基础上,判断当前迭代的字段是否为非null的 object 对象,如果是,递归浅拷贝处理. 综上所述, 然后考虑了数组对象, 我自己写了一个js版的拷贝函数,如下:
function cloneObject( o, d ) { if ( o === null || o === undefined || typeof ( o ) !== 'object' ) { return o; } var deep = !!d; var cloned; if ( o.constructor === Array ) { if ( deep === false ) { return o; } cloned = []; for ( var i in o ) { cloned.push( cloneObject( o[i], deep ) ); } return cloned; } cloned = {}; for ( var i in o ) { cloned[i] = deep ? cloneObject( o[i], true ) : o[i]; } return cloned; }
其中o是要被拷贝的对象, d指定是否要深拷贝 , 逻辑说明如下:
1 . 判断对象是否为null ,undefined, 或非object对象,如果是, 直接返回对象
2. 判断对象是否为数组,如果是,并且指定了要深拷贝,则遍历数组对象,对其成员进行深拷贝, 如果没指定为深拷贝,则直接返回数组
3. 如果是非数组对象, 遍历成员并递归处理成员对象,最后返回拷贝