网上关于as3的数据深复制方法流传已久,甚至在黑羽大神所著的《ActionScript 3.0殿堂之路》一书中也对该方法进行了介绍,然而我们需要注意的是该方法的适用范围却都没有多少人提及。
出于工作需要,我对该方法进行了验证,这里为像我一样的非大神开发者指出该方法的一点误区!
首先,从我们所提及的方法开始,下面是该方法的实现代码:
//随意声明两个变量,将其所持引用存放在foo数组内
var obj:Object = {name: "someone", web:"someurl"};
var arr:Array = [1,2,3];
var foo:Array = ["somewords", arr, obj];
//声明ByteArray变量,将foo写入字节流
var fooBA:ByteArray = new ByteArray();
fooBA.writeObject( foo );
//声明一个新的数组,并读取字节流数据
fooBA.position = 0;
var newFoo:Array = fooBA.readObject() as Array;
//通过更改新数组内的元素与foo比较,从而确定newFoo是对foo进行深复制所得,而非单纯浅复制
newFoo[1][2] = "new foo";
trace(foo);
trace(newFoo);
//输出结果
//somewords,1,2,3,[object Object]
//somewords,1,2,new foo,[object Object]
从中不难看到,foo的复制对象newFoo中的元素发生了变更,而foo则保持不变,所以两个数组的不同位置所持有的是指向不同对象的引用。
但是,假设我们所要复制的并非内置的Array或者Object类型,而是自定义类型对象呢,那么这个方法是否依然适用呢?
答案是否定的!
为了验证,我自定义了一个Player类,Player类对象包含了一个公开的name属性以及一个公开的say()方法:
class Player
{
public var name:String;
public function say():void
{
trace("helllo");
}
}
使用同样的方法进行验证:
var player_1:Player = new Player();
player_1.name = "player_1";
var ba:ByteArray = new ByteArray();
ba.writeObject( player_1 );
ba.position = 0;
var player_2:Player = ba.readObject() as Player;
trace(player_2);
//输出结果: null
输出结果为null的原因,是因为对从ba中获取的对象进行类型转换失败,重新获取的对象并非是Player类对象(至于是否有其他方法可以将从字节流中读取的数据还原为其本来的类型,目前我还不清楚,如果有人知道方法敬请告知)。
那么,如果不进行类型转换呢,我们能得到一个什么状态的object 对象:
var player_1:Player = new Player();
player_1.name = "player_1";
var ba:ByteArray = new ByteArray();
ba.writeObject( player_1 );
ba.position = 0;
var obj:Object = ba.readObject();
trace(obj.name);
trace(obj.say);
//输出结果:
//player_1
//undefined
由此可见,在写入字节流时,player_1的公开属性得以保留,而其方法与类型则被舍弃(私有属性与私有方法同样会被舍弃)。
因此,该方法准确来说是对一个对象的公开状态进行了深度复制。