Java程序员的ActionScript3学习笔记(二) 数组

数组基础

以前在读《Javascript 语言精粹》的时候读到,Javascript并没有提供真正的数组,而是提供了一种拥有一些“类数组”特性的对象(Array Like Object),它把数组的下标转换为字符串用作其属性。这样的数组明显比一个真正的数组慢,但是方便使用,它有自己的字面量表示法以及方法。

对于ActionScript3,其数组形式跟JavaScript一样。比如下面这个例子就很有趣:

package com.powerflasher.SampleApp {
	import flash.display.Sprite;

	public class FDTTest extends Sprite {
		public function FDTTest() {
			var array:Array =  ["Sam", "Jack", "Peter"];
			array["7"] = "Nick";
			array[-1000] = "Jason";
			
			trace("array[-1000] = " + array[-1000]);
			trace("array.length = " + array.length);
			
		}
	}
}

最后输出的结果是:

array[-1000] = Jason
array.length = 8

我们再用JavaScript来编写同样的代码:

var array = ["Sam","Jack","Peter"];

array["7"] = "Nick";

array[-1000] = "Jason";

alert("array[-1000] = " + array[-1000]);
alert("array.length = " + array.length);

最后弹框输出的结果与ActionScript的是一致的。

我们看到ActionScript中数组与对象的差别唯一不同就是属性名,数组的属性名只能用整数,正负都可以,并且不需要连续。对于数组值的类型也没有任何限定,一个数组里面可以包含各种类型的元素。
另外一个比较有意思的就是数组的长度,从上面的例子可以看出数组的长度是数组最大的正整数索引+1。我们上个例子只是定义了array[-1000], array[0], array[1], array[2], array[7], 那么我如果引用一个没有定义的数组元素呢?比如array[6],那么得出来的值将会是undefined,这跟访问一个不存在的对象属性是一样的。

数组的浅复制和深复制

在使用Java的时候涉及到集合的序列化和拷贝的时候需要考虑浅复制还是深复制的问题。不仅仅是Java,使用引用来操作对象的语言应该都会有这个问题。ActionScript也不例外。

可以理解浅复制就是只复制集合中对象的引用,而深复制会复制对象的本身。

ActionScript对数组进行浅复制非常的简单,只需要调用数组本身的slice方法或者contact方法就可以。slice方法是从参数的指定范围截取一个新的子数组返回,concat可以将参数拼成一个新数组返回。当不传递任何参数给这两个方法的时候将会完成数组的浅复制。

package com.powerflasher.SampleApp {
	import flash.display.Sprite;

	public class FDTTest extends Sprite {
		public function FDTTest() {
			var array1:Array = ["Sam", ["Jack", "Peter"]];
			var array2:Array = array1.concat();
			
			trace("array2:" + array2);
			array2[1][1] = "Tom";
			
			trace("array1:" + array1);
			trace("array2:" + array2);
		}
	}
}

最终输出的结果是:

array2:Sam,Jack,Peter
array1:Sam,Jack,Tom
array2:Sam,Jack,Tom

因为array2和array1持有对同一个元素的引用,通过array2进行改变,array1也改变了。

如果要进行深复制,那该怎么做呢?需要借助ByteArray这个类型的对象,ByteArray是一个byte数组的封装,提供了操作byte缓冲区的一些方法,跟Java中的java.nio.ByteBuffer类似。

package com.powerflasher.SampleApp {
	import flash.utils.ByteArray;
	import flash.display.Sprite;

	public class FDTTest extends Sprite {
		public function FDTTest() {
			var array1:Array = ["Sam", ["Jack", "Peter"]];
			var byteArray:ByteArray = new ByteArray();
			byteArray.writeObject(array1);
			byteArray.position = 0;
			var array2:Array = byteArray.readObject() as Array;
			trace("array2:" + array2);
			array2[1][1] = "Tom";
			trace("array1:" + array1);
			trace("array2:" + array2);
		}
	}
}

输出结果:

array2:Sam,Jack,Peter
array1:Sam,Jack,Peter
array2:Sam,Jack,Tom

有两点挺有意思,一是ByteArray跟java.nio.ByteBuffer不一样,没有提供flip方法,当数据写进byte缓冲区之后要再读出来,需要手工将position指向0;二是用as运算符做类型转换是一个比较优雅的解决方案,用一条语句即检查了类型又做了转换,而且不会抛异常,在Java中这是一个很烦的过程,需要先instanceof判断,在进行转换,如果不判断,类型错了还会抛出ClassCastException这种运行时异常。

操作数组的每个元素

ActionScript是一种支持函数式风格的编程,在actionscript中,函数是Function类型的对象,函数可以作为其它函数的参数进行传递进行回调。个人感觉函数回调这种风格用的比较多的地方一个是事件的处理,一个是操作集合。

ActionScript数组提供了针对数组每个元素操作的方法,这些方法都是在函数回调的基础之上构建的。操作有以下几种:

forEach(callback:Function, thisObject:* = null):void  //针对数组中的每一个元素进行操作

filter(callback:Function, thisObject:* = null):Array //指定一个过滤条件,从原数组中过滤出符合条件的新元素返回这些新元素的数组,回调函数返回单个新数组的元素。

map(callback:Function, thisObject: * = null):Array //使用回调函数来操作数组中的每一个值,并利用回调函数返回的结果组成新的数组返回。

some(callback:Function, thisObject: * = null):Boolean //只要有一个元素回调的结果为true就返回true

every(callback:Function, thisObject: *  = null):Boolean //需要全部的元素回调结果返回true才返回true

以上方法回调函数的形式都是: function 回调函数名(currentElement:Object, index:int, array:Array):返回值类型{}, 需要注意函数的类型必须符合这种形式,否则执行时会出现错误。

数组排序

Java中没有函数回调,只能定义接口来模拟函数回调。 http://my.oschina.net/chihz/blog/52913,在Java中集合排序是通过定义Comparator<T>接口。
ActionScript支持函数回调,就不用使用接口这么笨重的东西了:

package com.powerflasher.SampleApp {
	import flash.display.Sprite;

	public class FDTTest extends Sprite {
		public function FDTTest() {
			var array:Array = [100, 9, 200, 2];
			array.sort(function(arg1:int, arg2:int):int {
				return arg1 - arg2;
			});
			trace("array:" + array);
		}
	}
}


你可能感兴趣的:(Java程序员的ActionScript3学习笔记(二) 数组)