一:for each ... in
与 for..in 一样都是自动遍历对象的属性,不同的是for each...in 更像是为遍历保存键值对的集合而产生的,而这些集合的类型可以是未声明类型的对象,甚至XML文件,而在遍历时循环中的循环变量类型声明是用"*"号来表示,意为任意类型。
1:遍历未声明类型对象:
var arr:Object = {1:"jack",2:2046};
for each(var i:* in arr)
{
trace(i);
}
/-----
jack
2046
2:遍历XML:
var xml:XML = <beans>
<bean>jack</bean>
<bean>2046</bean>
</beans>;
for each(var item:* in xml.bean)
{
trace(item);
}
/-----
jack
2046
二:break的特殊用法:
在AS3中,由于其作用于动画的特殊性,孕生出很有意思的的label标签用法。此label标签不能独立存在,必须依赖break、continue两个跳转关键字进行使用。
gotoout:for(var i:int = 0; i < 10; i++)
{
for(var j:int = 0; j < 10; j++)
{
trace("i:" + i + ",j:" + j);
if((i==0)&& (j==8)){
break gotoout;
}
}
}
/-----
i:0,j:0
i:0,j:1
i:0,j:2
i:0,j:3
i:0,j:4
i:0,j:5
i:0,j:6
i:0,j:7
i:0,j:8
在这里gotoout标签包含了一个嵌套for循环,之中退出条件为 i=0 && j==8 时,则跳转出整个循环;如换为continue则为:
gotoout:for(var i:int = 0; i < 10; i++)
{
for(var j:int = 0; j < 10; j++)
{
if((i==0)&& (j==8)){
trace("跳过第i:" + i + " j:" + j +"次循环");
continue gotoout;
}
else
{
trace("i:" + i + ",j:" + j);
}
}
if((i==1))
{
break;
}
}
/---------
i:0,j:0
i:0,j:1
i:0,j:2
i:0,j:3
i:0,j:4
i:0,j:5
i:0,j:6
i:0,j:7
跳过第i:0 j:8次循环
i:1,j:0
i:1,j:1
i:1,j:2
i:1,j:3
i:1,j:4
i:1,j:5
i:1,j:6
i:1,j:7
i:1,j:8
i:1,j:9
当然也不一定是循环才能使用breank,但continue一定要配合循环使用
break:
trace("1");
gotoout:{
trace("2");
trace("3");
break gotoout;
trace("4");
trace("5");
}
/-------
trace("1");
gotoout:{
trace("2");
trace("3");
break gotoout;
trace("4");
trace("5");
}
continue:
trace("1");
gotoout:{
trace("2");
trace("3");
continue gotoout;
trace("4");
trace("5");
}
/-------
1039: 找不到 continue 语句的目标。
标签也可嵌套使用,但无论嵌套几层,最终跳出哪层标签由 break 标签名 决定的
trace("1");
gotoout:{
gotoout1:{
gotoout2:{
trace("2");
trace("3");
break gotoout2;
trace("4");
trace("5");
}
trace("gotoout1");
}
trace("gotoout");
}
/------
1
2
3
gotoout1
gotoout
如break gotoout2 换成 break gotoout ,则程序会直接跳出gotoout标签,不会打印 gotoout1、gotoout。
三:局部变量可当全局变量使用
AS3的代码编译是提交给Flash Play优化后编译,因此会出现在java和C++中不可想象的状况。
for(var i:int =1; i<=3; i++)
{
var str:String = "你好,正在循环";
trace(i + ":循环内:" + str);
}
trace("循环外:" + str);
/-----
1:循环内:你好,正在循环
2:循环内:你好,正在循环
3:循环内:你好,正在循环
循环外:你好,正在循环
可以看到str是在for循环开始后在循环内部声明并赋值的,但在循环结束后在循环外部依然正常使用了str这个变量,这是由于代码在编译过程中编译器将声明前置优化了。
var str:String;
.......
因此无论将var str:String 放在代码块的何处,编译器总会将变量声明优化前置。但为了程序的可维护性,最好还是按照java、C++等语言的严谨写法书写代码。
局部变量虽可随处声明,但注意其赋值的有效性,如:
trace("循环外:" + str);
for(var i:int =1; i<=3; i++)
{
var str:String = "你好,正在循环";
trace(i + ":循环内:" + str);
}
/-----
循环外:null
1:循环内:你好,正在循环
2:循环内:你好,正在循环
3:循环内:你好,正在循环
程序在变量未赋值前就使用此变量,虽可编译运行,但最终打印出str的值为null。
四:函数表达式
这一点很像js的匿名函数,可以说完全相同。
var func:Function = function(par:int){
return par*8;
}
trace(func(8));
/-------
64
声明了类型为Function名为func的变量,此变量的值很怪异,看上去完全是个函数,其实函数本身也是对象,把对象赋值给变量有什么不对呢?虽然java有匿名类、C#也引入了匿名函数,但它们因为的实现方式肯定没有js与as3直观和简洁。匿名函数是由变量记录这个无名函数的内存地址,而外部访问是由变量作为介质的,因此删除变量,等于删除了这个无名函数。但值得注意的是,函数表达式本身的书写方式导致不宜维护,因此如果没有特别需要毋须将函数写为匿名函数。
五:arguments
AS3函数使用中,可以给函数传入一系列的参数,如:
function sub(par1:int,par2:int)
{
.....
}
在这之中,当参数传入函数调用之后,AS3编译器会生成一个名为arguments数组对象,它保存了当前函数传入的参数的值,可以看作参入参数的备份。
function sub(par1:int,par2:int)
{
par1 = 3;
par2 = 4;
var sub1:int = par1 + par2;
var sub2:int = arguments[0] + arguments[1];
trace("函数参数之和:" + sub1);
trace("arguments之和:" + sub2);
}
sub(1,2);
/--------
函数参数之和:7
arguments之和:3
但这个备份数组仅限于参数是按值传递的情况下,如参数是以引用传递则arguments的值会跟着改变。
function sub(par:Array)
{
par[0] = "jack";
trace("函数参数:" + par);
trace("arguments:" + arguments);
}
var arr:Array = new Array(1,2,3);
sub(arr);
/--------
函数参数:jack,2,3
arguments:jack,2,3
另外,arguments有个重要属性:callee,就是call自己。如使用该属性,程序会将arguments所在的当前函数按照callee的赋值再次执行一次
var bool:Boolean = true;
function sub(par:Array)
{
par[0] = "jack";
trace("函数参数:" + par);
trace("arguments:" + arguments);
if(bool)
{
bool = false;
var arrbak:Array = new Array("开始执行callee",1,1);
trace("开始执行callee");
arguments.callee(arrbak);
}
}
var arr:Array = new Array(1,2,3);
sub(arr);
/--------
函数参数:jack,2,3
arguments:jack,2,3
开始执行callee
函数参数:jack,1,1
arguments:jack,1,1
六、重载
一种OOP语言拥有重载特性是很习以为常的事,毕竟任何OOP语言都必须遵循OOP三大特质。有意思的是AS中,重载这样在其他语言司空见惯的特性,在AS3出现以前都是不存在的(不仅AS,javascript、vbScript、ruby等常见脚本语言都不支持,到底是脚本啊 .... ),且AS3的重载说到底也是模拟重载,一种数组变通而已。
1:使用aruments的length属性进行重载
function test(par1:int):void
{
if(arguments.length == 1)
trace("重载1");
else if(arguments.length >1)
trace("重载2");
else
trace("重载3");
}
test(1);
test(1,2);
test(1,2,3);
/--------------------
重载1
重载2
重载2
注意函数test在声明时只声明了 par1:int 一个参数,而在调用时程序连续调用了3次test,并且后两次参数与函数声明不符,多了。但编译器如果运行在标准模式下编译,是不会报错也可以运行的,这样arguments数组会扩大为你传进来参数的个数,如test(1,2,3),arguments长度就是3了,程序中如果需要用到2、3,只能通过arguments[1]/[2]来找到多出的参数。用arguments时,注意编译器一定要运行在标准模式下;参数只能比函数声明多,不能少。
2:使用 ...(args) 来传入不同参数。
注意:...(args) ,前面是3点,英文模式下的3点,不多不少。args是传进来参数数组的名称,可以任意。
function test(...args):void
{
if(args.length == 1)
trace("重载1");
else if(args.length >1)
trace("重载2");
else
trace("重载3");
}
test(1);
test(1,2);
test(1,2,3);
/--------------------
重载1
重载2
重载2
当使用...args ,在程序中就不能用arguments来获取参数了,取而代之是args。...args 也可以与声明参数一起使用
function test(par1:int,...args):void
{
if(args.length == 1)
trace("参数" + par1 + " 重载1 args参数:" + args);
else if(args.length == 2)
trace("参数" + par1 + " 重载2 args参数:" + args);
else
trace("参数" + par1 + " 重载3 args参数:" + args);
}
test(1,1);
test(1,2,3);
test(1,2,3,4,5);
/---------------------
参数1 重载1 args参数:1
参数1 重载2 args参数:2,3
参数1 重载3 args参数:2,3,4,5
这样也变通模拟了函数重载,args是不需要编译器标准的无论在严谨或标准模式都可运行;args使用后arguments不能使用包括其属性;在给已声明参数赋值后,接下来无论多少个参数编译器都会将其作为数组传给args。