基元数据和复杂数据区别
基元数据类型: 存放的是实际的值,赋值之后,相当于深拷贝。
复杂数据类型: 存放的是指针(地址),赋值之后,相当于浅拷贝。
?
?
?
?
?
先来看下面的代码:
var initialObj:Object=new Object();
initialObj.name="名字";
var afterObj:Object=initialObj;
afterObj.name="改名了";
trace("initialObj的名字:"+initialObj.name);//输出“改名了”
trace("afterObj的名字:"+afterObj.name);//输出“改名了”
如果是新手,可能你会紧张的发现initialObj的名字也变成了"改名了",但并没有更改过他的名字啊
首先要知道的是AS3里总的分为两种数据类型——基元数据类型也叫原始数据类型和复杂数据类型也叫引用数据类型,具体是什么可以到网上查下相关资料。
因为Object是一个复杂数据类型把initialObj赋值给afterOb(就是这行var afterObj:Object=initialObj;)其实是把initialObj和afterOb指向内存中的同一地址,所以改变了 afterObj,initialObj也改变了。
如何复制一个和initialObj一模一样的对象,而更改复制的对象又不影响initialObj呢,就要用到下面的复制方法,统称“深复制”
//声明一个Object类型的变量initialObj,并添加一个名为name的属性,属性值为“名字”
var initialObj:Object=new Object();
initialObj.name="名字";
//声明ba并把initialObj写入到ba中,也就是使用二进制数据存储initialObj
var ba:ByteArray=new ByteArray();
ba.writeObject(initialObj);
ba.position=0;
//声明afterObj并从ba读取initialObj,其实读取的是和initialObj长的一模一样的一个对象,并不是 initialObj
var afterObj:Object=ba.readObject();
afterObj.name="改名了";
trace("initialObj的名字:"+initialObj.name);//输出“名字”
trace("afterObj的名字:"+afterObj.name);//输出“改名了”
?
?
?
?
?
?
2:例子区别
as3 的值和引用在此整理一下:
as3 的值和引用这两者比较有关系的是“赋值”和“函数传参”两个行为,期间又需要分“基元类型”和“对象”来讨论。
我们知道Flash as语言中所有的数据类型都继承自Object,包括基元数据类型,但是在值和引用操作时它们的确需要区别对待。
我们将基元数据类型称为“非结构对象”,与之对应的其他Object称为“结构对象”。
下面将进行几种实验,结论大概就是
1、 基元数据类型按照值操作,代表基元数据的非结构对象也是按照值操作的。
2、 结构对象一般按照“引用”操作,但需要注意交换赋值的情况
3、 As3中的“引用”操作其实不是真正意义上的引用,只是类似于“指针”传递的一种伪“引用”。As3中所有操作底层意义都是值操作,只不过针对结构对象时是“指针”值的值操作。
4、 As3中的函数传参,对基元类型相当于新副本的值操作。对结构对象,相当于“指针”值新副本的值操作。
5、 必要的时候使用深层次拷贝操作,特别是在多层次框架结构中。
=================
基元类型(包括 Boolean、Number、int、uint 和 String)
赋值:按照值操作。
var a:int=3;
var b:int=a;
b=6;
trace(a,b);// 3 6 即 b的改变不会带来a的改变
函数传参:按照值操作
var a:int=3;
function f1(b:int):void{
??? b=6;
}
f1(a);
trace(a);//3 即在函数内部生成了新副本,其变化不会带来a的改变
与前面的赋值操作是等价一致的
=================
对象Object
赋值:按照引用操作
var a:Object={x:1,y:2};
var b:Object=a;
b.x=6;
trace(a.x);//6 即 b的改变会带来a的改变
—-下面模拟复杂对象赋值—
var c:Object={i:10,j:11}
var a:Object={x:1,y:c};
var d:Object=a.y;
var b:Object=a;
d.i=6;
trace(a.y.i);//6
trace(b.y.i);//6 这里需要格外注意,as3的引用行为是无孔不入的,自定义对象的子对象遭遇引用操作,特别是多层架构中,隐蔽的引用操作会带来意想不到的问题。
函数传参:结构对象按引用操作;代表基元类型的非结构对象,按值操作
var a:Object={x:3};
function f1(b:Object):void{
??? b.x=6;
}
f1(a);
trace(a.x);//6 一如既往的引用操作,但请注意下面
—–代表基元类型的对象—-
var a:Object=Object(3);
function f1(b:Object):void{
??? b=6;
}
f1(a);
trace(a);//3 如果Object代表基元类型,那则按值来操作
=============================
貌似到这里关于as3的值和引用归类总结已经结束了,其实不是的。
看下面一段代码。
var a:Object={x:1};
var b:Object={x:4};
var c:Object;
c=a;
a=b;
b=c;
trace(a.x,b.x);
结果不出意外的是 4 1 ,我们继续看下面代码
var a:Object={x:1};
var b:Object={x:4};
function swapObj(i:Object,j:Object):void
{
???????? var k:Object;
???????? k=i;
???????? i=j;
???????? j=k;
}
swapObj (a,b);
trace(a.x,b.x);
结果是什么呢?却不是我们想的 4 1,而是 1 4
这里发生了什么故事,我们继续试验
var a:Object={x:1};
var b:Object={x:4};
function swapArr(i:Object,j:Object):void
{
???????? var k:Object;
???????? k=i;
???????? k.x+=10;
???????? trace(k.x,a.x,b.x,i.x,j.x);
???????? i=j;
???????? trace(k.x,a.x,b.x,i.x,j.x);
???????? j=k;
???????? trace(k.x,a.x,b.x,i.x,j.x);
}
swapArr(a,b);
trace(a.x,b.x);
————————
11 11 4 11 4
11 11 4 4 4
11 11 4 4 11
11 4
看起来很让人头疼,我直接画图摆结论吧,as3所谓的引用操作过程中只是指针值的操作,并不是真的引用。
至此,as3值和引用操作真正有价值的东西才算讲了一点点。
要善用函数返回值,不要想当然的把对象传进去就认为函数自己会按照引用操作去完美的工作。
遇到可能出现这种问题的情况,要善用深层次拷贝。
比如比较常用的Array,默认并没有提供clone函数,那就按照如下操作进行深层次拷贝,来保证代码流转过程中的逻辑正确和减少未知引用关联。
import flash.utils.ByteArray;
function clone(source:Object):*
{
??? var myBA:ByteArray = new ByteArray();
??? myBA.writeObject(source);
??? myBA.position = 0;
??? return(myBA.readObject());
}