ActionScript 是一种运行在 Flash player 环境下的编程语言,它为 Flash 影片和应用程序提供交互、数据操作等功能。Flash Player 通过其虚拟机执行ActionScript、ActionScript 代码通常通过编译器(Flash Professional、Flex Builder、Flex SDK 或 Flex Data Services 中的)编译成二进制代码。编译好的代码内置于 SWF 中,该代码有 Flash Player 的运行环境下被执行。
ActionScript 3.0 作为 ActionScript 最新版本新增了不少功能。本文仅以 ActionScript 3.0 为例讲解。
ActionScript 3.0 简介
相对于 ActionScript 2.0,ActionScript 3.0 为哪些熟悉 OOP 编程的开发人员提供健壮的模式。
- 语法方面的增强和改动
- 引入了
package
(包) 和namespace
(命名空间) 两个概念。其中 package 用来管理类定义,防止命名冲突,而 namespace 则用来控制程序属性方法的访问。 - 新增内置类型
int
(32 比特整数),uint
(非负 32 比特整数),用来提速整数运算; - 新增
*
类型标识,用来标识类型不确定的变量,通常在运行时变量类型无法确定时使用。 在 ActionScript 2.0 中这种情况下需要用 Object 赖作为类型表识; - 新增
is
和as
两个运算符来进行类型检查。其中is
代替 ActionScript 2.0 中的instanceof
来查询类实例的继承关系,而as
则是用来进行不抛错误的类型转换。 - 新增
in
运算符来查询某实例的属性或其prototype
中是否存在指定名称的属性。 - 新增
for each
语句来循环操作 Array 及 Object 实例。 - 新增
const
语句来声明常量。 - 新增
Bound Method
概念。当一个对象的方法被付值给另外一个函数变量时,此函数变量指向的是一个 Bound Method,以保证对象方法的作用域仍然维持在声明此方法的对象上。这相当于 ActionScript 2.0 中的mx.util.Delegate
类, 在 ActionScript 3.0 中这个功能完全内置在语言中,不需要额外写代码。 - ActionScript 3.0 的方法声明中允许为参数指定默认值(实现可选参数)。
- ActionScript 3.0 中方法如果声明返回值,则必须明确返回。
- ActionScript 2.0 中表示方法没有返回值的
void
标识, 在 ActionScript 3.0 中变更为void
。
- OOP 方面的增强
通过类定义而生成的实例,在 ActionScript 3.0 中是属于 Sealed
类型,即其属性和方法无法在运行时修改。这部分属性在 ActionScript 2.0 中是通过类的 prototype
对象来存储,而在 ActionScript 3.0 中则通过被称为 Trait
的概念对象存储管理,无法通过程序控制。这种处理方式一方面减少了通过 prototype
继承链查找属性方法所耗费的时间(所有父类的实现方法和属性都会被直接复制到对应的子类的 Trait
中),另一方面也减少了内存占用量,因为不用动态的给每一个实例创建 hhahtable 来存储变量。如果仍然希望使用 ActionScript 2.0 中类实例在运行时的动态特性,可以将类声明为 dynamic
。
- API 方面的增强
- 新增 Display API, 使 ActionScript 3.0 可以控制包括
Shape
、Image
、TextField
、Sprit
e、MovieClip
、Video
、SimpleButton
、Loader
在内的大部分 DisplayList 渲染单位。这其中 Sprite 类可以简单理解为没有时间轴的 MovieClip,适合用来作为组件等不需要时间轴功能的子类的基础。而新版的 MovieClip 也比 ActionScript 2.0 多了对于 Scene(场景)和 Label(桢标签)的程序控制。另外,渲染单位的创建和销毁通过联合 new 操作符以及 addChild/removeChild 等方法实现,类似 attachMovie 的旧方法已被舍弃,同时以后也无须去处理深度值。 - 新增 DOM Event API,所有在 DisplayList 上的渲染单位都支持全新的三段式事件播放机制, Stage 为起点自上而下的播报事件到
target
对象,此过程称为Capture Phase
),然后播报事件给target
对象(此过程称为Target Phase
),最后在自下而上的播报事件(此过程称为Bubbling Phase
)。 - 新增内置的 Regular Expressions(正则表达式)支持,使 ActionScript 3.0 能够高效地创建、比较和修改字符串,以及迅速地分析大量文本和数据以搜索、移除和替换文本模式。
- 新增 ECMScript for XML(E4X)支持。 E4X 是 ActionScript 3.0 中内置的 XML 处理语法。 在 ActionScript 3.0 中 XML 成为内置类型,而之前的 ActionScript 2.0 版本 XML 的处理 API 转移到 Flash.xml.*包中,以保持向下兼容。
- 新增 Socket 类,允许读取和写入二进制数据,使通过 ActionScript 来解析底层网络协议(比如 POP3, SMTP, IMAP, NNTP)等成为可能,使 Flash Player 可以连接邮件服务器和新闻组。
- 新增 Proxy 类来替代在 ActionScript 2.0 中的
Object.__resolve
功能。 - 新增对于 Reflect(反射)的支持,相关方法在
Flash.util.*
包中。
- 与 ActionScript 2.0 类的语法差别
其实,ActionScript 3.0 类与 ActionScript 2.0 的语法差别不是很多,因此如果你是一个有经验的 ActionScript 2.0 程序员,基本上不用担心。下面说就我知道的差别做一个小结。
- ActionScript 3.0 中引入了包的概念,主要是解决类名称冲突,这一点和 Java 类似。 在 ActionScript 3.0 类中必须在包中声明。 而 ActionScript 2.0 是用类的完全限定的名称来实现相同的功能,类不能用
public
修饰; - ActionScript 3.0 中可以使用命名空间,命名空间好比是自定义是类成员访问符,声明之后用
using
命名空间来访问,这一点和 C# 相似。 - ActionScript 3.0 中使用
private
属性只对对同一类中的引用可见。 而 ActionScript 2.0 中 private 属性允许子类访问超类中的私有属性。 - ActionScript 3.0 中标记为
private
的属性在编译时和运行时都不可用,而在 ActionScript 2.0 中 private 关键字只在编译时禁止访问。 - ActionScript 3.0 中 protected 属性是 ActionScript 3.0 中的新增属性,对同一类及子类中的引用可见,这一点类似于 ActionScript 2.0 的
private
关键字。 - ActionScript 3.0 中对类属性时可以直接赋值等同于构造函数中进行初始化,即使类属性是数组或对象也如此。ActionScript 2.0 中如果属性是数组或对象,很可能将它们静态化。点击此处下载源文件。
- ActionScript 3.0 中允许在同一类中定义同名的静态属性和实例属性,新增静态常量和
const
关键字。 - ActionScript 3.0 类的方法作为参数传递给函数或值从函数返回时,
this
总是引用实现方法的实例。 但 ActionScript 2.0 并不总是这样,因此很多时候不得不在函数外部声明地个变量引用this
,甚至使用 Delegate。点击此处下载源文件。 - ActionScript 3.0 中子类覆盖父类方法必须使用
override
关键字。
基本开发流程
Flash 和 Professional Flex Builder 下面我们就用 Flex Builder 来编写并运行第一个 ActionScript 3.0 程序。
步骤
ActionScript 3.0 最好的 IDE 应该是 Flex Builder。下面我们就用 Flex Builder 来编写并运行第一个 ActionScript 3.0 程序。
- 新建工程。点选工具栏中的 New 按钮,从弹出的菜单中选择 ActionScript Project。如下图:
在弹出的对话框中输入 HelloWorld
作为项目名称。单击下一步,主程序文件名默认下为 HelloWorld
,输出文件夹名为 bin
。我们不作更改,按 Finish
确定。如下图:
- 编写代码。打开 Flex Builder 生成的
HelloWorld
文件,可以看到输入 Flex Builder 已经为我们编写好了 HelloWorld 类的架构,我们只需添加下列代码(绿色部分):
package {
import Flash.display.Sprite;
import Flash.text.TextField;
public class HelloWorld extends Sprite
{
public function HelloWorld()
{
var tfResult:TextField=new TextField();
tfResult.text="Hello World";
addChild(tfResult);
}
}
}
在 ActionScript 3.0 中你必须用 addChild
方法将 display
对象加载到容器中,这一点和旧版明显不同。
- 运行测试。按 Ctrl + S 保存文件,在 Navigation 视图中右键单击该文件,然后点击
run
按钮运行程序。如下图:
我们将在浏览器中看到 HelloWorld的问候。
在 Flex 中使用 ActionScript 的三种方法
在 Flex 中使用 ActionScript,其实和在网页中使用 JavActionScriptcript 等脚本文件类似,主要有三种方式。
Flex 的核心是 MXML 和 ActionScript。MXML是用于为 Flex 应用程序进行用户界面组件布局,它属于表示层,最终要编辑成 ActionScript 并生成 ActionScript 类文件在 Flash Player 上运行。
如果你是个 Java 开发者就很好理解这一点,MXML 就好比是 JSP/Struts/JSF,它们最终都会编辑成 Java 类文件并在具备 Java 虚拟机环境的浏览器上运行。所以说,Flex最核心的还是 ActionScript。在 Flex 中,ActionScript 是类库的方式出现的,该类库包含组件(容器和控件)、管理器类、数据服务类和所有其他功能的类。
其实和在网页中使用 JavaScript 等脚本文件类似,主要有三种方式。
- 内联方式
这种方式直接将 ActionScript 方法作为事件的属性值,当然这种方法一般只有一行,相对简单。如果要给方法传递对数,这种方法就不可取了。 - 级联方式
这种方式将 ActionScript 方法放入<mx:Script></mx:Script>
代码块中,然后将方法作为事件的属性值,并可以在调用方法时传递参数,从而做到了 ActionScript 方法在一个文件中的重用。
<!--main.mxml -->
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:Button label="Say Hello" click="sayHello('Flying')"/>
<mx:Script>
<![CDATA[
import mx.controls.Alert;
private function sayHello(param_name:String):void {
Alert.show("Hello, "+param_name);
}
]]>
</mx:Script>
</mx>
- 外联方式
// myFunction.asimport
mx.controls.Alert;
private function sayHello(param_name:String):void {
mx.controls.Alert.show("Hello, "+param_name);
}
上述方式为 ActionScript 方法单独新建一个 ActionScript 文件,然后设置该方法为被调用文件的 Script 元素的 source 属性值,并可以在调用方法时传递参数,此文件可以在多个文件调用,从而实现了 ActionScript 方法在多个文件中的重用。
ActionScript 3.0 基础
变量和数据类型
变量都有相应的数据类型。 在 ActionScript 3.0 中,新增了 int、uint 简单数据类型。int 型变量主要用作循环计数器, 而 uint 型变量为无符号的 32 位整型,主要用作引用 RGB 色彩值。注意它们取整时将直接舍弃小数部分。看下面代码。
package {
import Flash.display.Sprite;
public class VariableDemo extends Sprite {
public function VariableDemo() {
for (var i: int = 1; i < 6; i++) {
trace(i);
}
var r: uint = 255;
trace(i);
var n1: int = 9.9;
trace(n1);
var n2: uint = 9.9;
trace(n2);
}
}
}
注意:void 简单数据类型是小写的。至于新增的复杂数据类型,有 RegExp 和 XMLList。
运算符和表达式
和 ActionScript 2.0 中的一样,ActionScript 3.0 运算符对应相应的表达式。
package {
import Flash.display.Sprite;
public class EODemo extends Sprite
{
public function EODemo(){
// 数值运算符
var price:Number=400+50;
trace(price);
price=price+50;
trace(price);
price=price*1.2;
trace(price);
price=price/2;
trace(price);
price=price%4;
trace(price);
// 字符串运算符
var bookTitle:String="ActionScript 3.0 ";
bookTitle = bookTitle+"& Flex 2.0 实战";
trace(bookTitle);
// 赋值运算符
price+=200;
trace(price);
// 关系运算符
trace(price>100);
// 逻辑运算符
trace(price>100&&price<100);
// 条件运算符
trace((price>100) ? "大于 100" : "不大于 100");
// new 运算符
var fruits:Array=new Array("apples", "oranges", "bananActionScript");
// 数组访问运算符[]
trace(fruits[0]);
// 点 (.) 运算符
trace(fruits.length);
// 按位运算符(|和>>)
fruits.sort(Array.CASEINSENSITIVE | Array.DESCENDING);
trace(price>>2);
}
}
}
流程语句
ActionScript 3.0 中新增了 for...each 循环语句,它最大的优点就是可以直接遍历 XML 或 XMLList 对象。
虽然都是循环语句,但 for...each 循环语句与 for...in 不同。
- for...each 循环语句遍历对象,循环变量包含属性值,而 for...in 循环语句无序遍历对象,循环变量包含属性名。
package {
import Flash.display.MovieClip;
public class StatementDemo extends MovieClip
{
public function StatementDemo(){
var i;
var myObj:Object = {x:20, y:30,z:50};
for (i in myObj)
{
trace(i);
}
for each (i in myObj)
{
trace(i);
}
}
}
}
- for...each 和 for...in 循环语句都可以顺序遍历数组的元素,但前者循环变量包含元素值,而后者循环变量包含元素下标。
package {
import Flash.display.MovieClip;
public class StatementDemo extends MovieClip
{
public function StatementDemo(){
var i;
var myArray:Array = ["one","two","three"];
for (i in myArray)
{
trace(i);
}
for each(i in myArray)
{
trace(i);
}
}
}
}
数组
数组是 ActionScript 的核心类之一,ActionScript 3.0 中新增了不少数组的方法,比如 indexOf
、lastIndexOf
、every
、some
、map
和 forEach
等。看下面实例代码:
package {
import Flash.display.Sprite;
public class ArrayDemo extends Sprite
{
public function ArrayDemo()
{
var production:Array=new Array();
production[0]=1000;
production[1]=1200;
production[2]=1300;
production[3]=1200;
production[production.length]=1000;
production.push(1250);
trace(production.length); // 6
trace(production[3]); // 1200
// 用 lastIndexOf 方法返回某个元素值第一次出现的位置
trace(production.indexOf(1200)); // 1
// 用 lastIndexOf 方法返回某个元素值最后一次出现的位置
trace(production.lastIndexOf(1200)); // 3
// 用 new 运算符声明一个关联数组(用{}运算符会更简捷)
var salesVolume:Array=new Array();
salesVolume["Jan"]=800;
salesVolume["Feb"]=1200;
salesVolume["Mar"]=1200;
salesVolume["Apr"]=1100;
salesVolume["May"]=800;
salesVolume["Jun"]=1200;
// 使用数组访问运算符 ([]) 访问数组元素值
trace(salesVolume["Apr"]); // 1100
// 使用点运算符 (.) 访问数组元素值
trace(salesVolume.Apr); // 1100
// 用 new 运算符声明一个以对象作为元素的关联数组,对象的属性为元素名,对象的属性值为元素值
var sale:Array=new Array();
sale.push({month:"Jan",volume:800});
sale.push({month:"Feb",volume:1200});
sale.push({month:"Mar",volume:1200});
sale.push({month:"Apr",volume:1100});
sale.push({month:"May",volume:800});
sale.push({month:"Jun",volume:1200});
// 用 every 方法遍历数组,检验其所有元素是不是符合某个标准,全部满足才返回 true
trace(sale.every(everySale)); // true
// 用 every 方法遍历数组,只要有一个符合某个标准就返回 true
trace(sale.some(someSale)); // true
// 用 filter 方法遍历数组,返回所有符合某个标准的元素组成的数组
trace(sale.filter(filterSale).length); // 4
// 返回由所有元素执行 map 的参数函数的返回值组成的新数组
var mapArr:Array = sale.map(mapSale);
trace(mapArr); // 900,1300,1300,1200,900,1300
// 返回所有元素执行 forEach 的参数函数的值
sale.forEach(traceSale); // Jan (800) Feb (1200) Mar (1200)...
}
private function everySale(item:*, index:int, array:Array):Boolean
{
return (item.volume >600);
}
private function someSale(item:*, index:int, array:Array):Boolean
{
return (item.volume >1100);
}
private function filterSale(item:*, index:int, array:Array):Boolean
{
return (item.volume >1000);
}
private function mapSale(item:*, index:int, arr:Array):int
{
return item.volume+100;
}
private function traceSale(item:*, index:int, arr:Array):void
{
trace(item.month + " (" + item.volume + ")");
}
}
}
Point 对象
高中时几何和物理学得不好,老是记不住一些公式,因此做 Flash 游戏就头大。现在好了,ActionScript 3.0 中的 Flash.geom
包中包含了用于定义几何对象(如点、矩形和转换矩阵)的类,以后做 Flash 游戏就方便多了。
Point 对象定义一对笛卡尔坐标。它表示二维坐标系中的某个位置。其中 x
表示水平轴,y
表示垂直轴。
- 确定两点之间的距离
// 定义 Point 对象
var pt1:Point = new Point(0, 0);
var pt2:Point = new Point();
// 平移坐标
pt2.offset(3,4);
var dist = Point.distance(pt1, pt2);
trace(dist);
看出来没?这就是勾股定理的一个简单应用。
按指定的角度和距离移动显示对象
ActionScript 3.0 以前按指定的角度和距离移动显示对象只能用
Math
类的方法,相当复杂。现在利用Point
对象的polar
方法方便地实现类似功能。看下面代码:
import Flash.geom.*;
import Flash.events.*;
// 创建圆形
var size:uint = 100;
var roundObject:Shape = new Shape();
roundObject.graphics.beginFill(0xFF0000);
roundObject.graphics.moveTo(size / 2, 0);
roundObject.graphics.curveTo(size, 0, size, size / 2);
roundObject.graphics.curveTo(size, size, size / 2, size);
roundObject.graphics.curveTo(0, size, 0, size / 2);
roundObject.graphics.curveTo(0, 0, size / 2, 0);
stage.addChild(roundObject);
// 移动圆形
var distance:Number = 100;
var angle:Number = 2 * Math.PI * (30 / 360);
var translatePoint:Point = Point.polar(distance, angle);
var dx:Number = translatePoint.x/5;
var dy:Number = translatePoint.y/5;
// 自定义侦听器函数
function onMove(e:Event):void {
var s:Shape = e.target as Shape;
s.x += dx;
s.y += dy;
if (s.x > 400) {
// 删除侦听器
roundObject.removeEventListener(Event.ENTER_FRAME,onMove);
}
}
// 注册侦听器
roundObject.addEventListener(Event.ENTER_FRAME, onMove);
polar
方法可以将一对极坐标转换为笛卡尔点坐标。Point
对象中还有 add
和 subtract
等其它方法,大家参看帮助文件吧。
使用 …(rest) 扩展 Event 参数对象属性
大家都知道,当发生事件时,Event对象将作为参数传递给事件侦听器,但 Event 对象将作为参数的属性是有限的。如果要传递特殊参数,一般会想到通过自定义事件类来实现。下面介绍一种更简单的方法:使用 ...(rest) 参数来扩展 Event 参数对象属性。
下面自定义了一个事件代理类:
package {
public class EventDelegate
{
public static function create(f : Function,... arg) : Function {
var isSame : Boolean = false;
var _f : Function = function(e : *,..._arg):void{
_arg = arg;
if(!isSame) {
isSame = true;
_arg.unshift(e);
}
f.apply(null, _arg);
};
return _f;
}
public static function toString() : String {
return "Event Delegate";
}
}
}
使用方法很简单:addEventListener(事件类型, EventDelegate.create(侦听器函数, 参数)),用法有点类似 AS2 中的 Delegate 类。
算法
一直以来数学学得不好,因此见了算法就头大,但有时又不得不面对。在实际开发中很多时候会作到算法。
递归
递归就是最常见的一种。下面我就来谈一谈自己的肤浅认识。
递归可以让一个函数从其内部调用其自身,递归和循环紧密相关,基本上能用循环就能用递归。一个典型示例就是计算阶乘,下面是其 ActipnScript 的代码。
// 阶乘
function factorial(n) {
if (n > 1) {
return n * factorial(n - 1);
} else {
return 1;
}
}
trace("6! = " + factorial(6));
此处我们定义了 factorial 函数,并在其内部调用自己,最后当 n=1时就返回 1,不再调用从而实现阶乘运算。著名的高斯算法一般是用循环来实现的,其实也可以用递归来实现。看下面代码:
// 高斯算法
function sum(min, max) {
if (max > min) {
return max + sum(min, --max);
} else {
return max;
}
}
trace("1 + 2 + ...+10=" + sum(1,10));
和循环一样,递归一定要有一个终结点,不然将导致计算机执行一个 无限死循环。
数组冒泡排序
数组排序有很多种算法。在冒泡算法中,较小的数组元素朝数组顶部逐渐冒上来,就像水中气泡上升一样,而较大的数组元素朝数组底部逐渐沉下去。这种算法用嵌套循环对整个数组数次遍历,每次遍历都比较数组中相邻的一对元素,如果它们以升序排列(或者值相等),那么它们的位置不变,否则交换它们的位置。看下面代码。
package {
public class Array2 {
public static function bubbleSort(array : Array) : void { // 冒泡排序
for (var i : uint = 0;i < array.length - 1; i++) { // 外层循环
for (var j : uint = 0;j < array.length - i - 1; j++) { // 内层循环
if (array[j] > array[j + 1]) {
var temp : uint = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
print(i + 1, array);
}
}
public static function print(time : uint,array : Array) : void {
trace("第" + time + "次排序:");
trace(array.toString() + " ");
}
}
}
用法很简单,如下所示。
Array2.bubbleSort(array);
/*
第 1 次排序:
4,5,3,7,0,9
第 2 次排序:
4,3,5,0,7,9
第 3 次排序:
3,4,0,5,7,9
第 4 次排序:
3,0,4,5,7,9
第 5 次排序:
0,3,4,5,7,9
*/
在冒泡算法中,外层循环的次数即是该算法的次数。
数组二叉查找算法
从数组中查找某一元素的最简单办法就是遍历数组中所有元素,然后和查找值比较,这种查找方式称作线性查找,它适用于未排序的小型数组。对于已排序的大型数组,可以使用二叉查找算法。
该算法首先找到数组中间位置的元素,并将其与查找值比较,如果相等,就返回该元素的索引;否则就将问题简化为查找数组的一半元素。如果查找值小于中间元素,就查找数组的前半部分,否则就查找数组的后半部分。看下面代码:
package {
import Flash.display.Sprite;
/**
* @author Flying
*/
public class Array2 extends Sprite {
public function Array2() {
var array : Array = [4, 5, 6, 7, 9, 13, 17];
trace("13的索引位置: " + indexOf(array, 13));
}
/** 采用二叉查找算法 */
public static function indexOf(array : Array, value : int) : int {
var low : int = 0;
var high : int = array.length;
var middle : int;
while (low < high) {
middle = (low + high) / 2; // 计算中间元素的索引
print(array, middle); // 打印数组,用于跟踪查找过程
if (array[middle] == value)
return middle;
if (value < array[middle])
high = middle;
else
low = middle;
}
return -1; // 没有找到该元素,返回-1
}
private static function print(array : Array, middle : int) : void {
for (var i : uint = 0;i < array.length; i++) {
trace(array[i]);
if (i == middle)
trace("*");
trace(" ");
}
}
}
}
/*
4 5 6 7* 9 13 17
4 5 6 7 9* 13 17
4 5 6 7 9 13* 17
13 的索引位置:5
*/
为方便测试,继承了 Sprite 类。
交换二维数组的行列
曾经用 Perl 做了一个项目,将 N 个某个目录下的 N 个 CSV 插入到 Sybase 数据库中,CSV是个交叉表,在处理时需要交换二维数组的行列。用 perl 来实现很简单,其实用 ActionScript 也不难。
代码如下:
package com.riafan.utils {
/**
* class that contains static utility methods for manipulating and working
* with Arrays
* @author Flying
* @version 1
* @tiptext
*/
public class ArrayUtil {
/**
* Switch the rows and columns of a 2d array array
* @param arr The 2d array whose dimensions will be switched
* @return A new array which contains items after switch
*/
public static function switchDimensions(arr : Array) : Array {
var newArr : Array = new Array();
var rowMax : uint = arr.length;
var colMax : uint;
try {
if(arr[0] is Array) {
colMax = arr[0].length;
}else {
throw new TypeError("muse be a 2d array");
}
}
catch (error : TypeError) {
trace(error.message);
}
for (var col : uint = 0; col < colMax; col++) {
var tmpArr : Array = new Array();
for (var row : uint = 0; row < rowMax; row++) {
tmpArr[row] = (arr[row][col]);
}
newArr[col] = tmpArr;
}
return newArr;
}
}
}
说明:switchDimensions方法用来交换初始二维数组的行列,并返回新的二维数组。比如说[[1, 2],[true, false], ['A','B']]
将返回 [[1, true, 'A'], [2, false, 'B']]
。
数组的最大两个元素求和
其实用数组的 sort
方法或 Math.max
方法不难求得数组最大两个元素的和,但有人觉得这样做性能不高。那我们就不使用这两种 ActionScript 方法,而通过比较遍历数组元素来实现。看下面代码:
function sumTwoLargest(arr:Array):int
{
var count:int = arr.length;
var largest:int;
var secondLargest:int;
var tmp:int;
for (var i = 0; i < count; i++) {
tmp = arr[i];
if (tmp > largest)
{
secondLargest = largest;
largest = tmp;
}
else if (tmp > secondLargest && tmp < largest)
{
secondLargest = tmp;
}
}
return largest + secondLargest;
}
var my_arr:Array = [1, 16, 16, 2, 18, 14, 18, 7];
trace(sumTwoLargest(my_arr));
注意第 13、14行,不能交换位置。这种算法是否真的性能更高,有待检验。
使用 ActiotScript 连接组合两个 Array
有两个关联数组,如何将其中一个关联数组添加到另外一个数组中,当然关联数组中得有一个相同的属性,该属性性对于源数组是唯一的,对于目标数组可以重复或为空。这就好像是 SQL 中用 inner join 关键字将两个表通过外键连接起来。看下面的代码:
package com.riafan.utils
{
public class ArrayUtil
{
public static function innerJoin(targetArr:Array,
sourceArr:Array, key:String):void
{
var targetCount:int = targetArr.length;
var sourceCount:int = sourceArr.length;
for (var i:int = 0; i < targetCount; i++)
{
var targetItem:Object = targetArr[i];
for (var j:int = 0; j < sourceCount; j++)
{
var sourceItem:Object = sourceArr[j];
if (targetItem[key] == sourceItem[key])
{
for(var prop:String in sourceItem)
{
if(prop != key)
{
targetItem[prop] = sourceItem[prop];
}
}
}
}
}
}
}
}
注意到我们这里用三层循环,最里层循环将源数组中的所有属性添加到目标数组中,当然作为外键的数组在目标数组中已经存在就不用加了。
使用实例如下:
var students:Array = [
{sid:201013018, sname:'Jim', sage:17, tid:2163},
{sid:201013021, sname:'John', sage:18, tid:2163},
{sid:201013025, sname:'Kite', sage:17, tid:2104}
];
var teachers:Array = [
{tid:2163, tname: 'Smith', tage:30},
{tid:2104, tname: 'Tom', tage:32},
{tid:2102, tname: 'Jane', tage:31}
];
ArrayUtil.innerJoin(students, teachers, 'tid');
trace一下 students 数组,已经添加了老师的姓名和年龄。
ActionScript 3.0 设计模式类图
最近看了 ActionScript 3.0 Design Pattern 一书,该书主要介绍了常用的 ActionScript 3.0 设计模式,确实是一本 ActionScript 3.0 OOP 好书。不过,我发觉作者在介绍设计模式时,少了类图。以方便大家更好地理解 ActionScript 3.0 的设计模式,特意用 EA 画了此书中用到的设计模式类图。
- Factory(工厂)模式
- Singleton(单例)模式
- Decorator(装饰)模式
- Adapter(适配器)模式
- Composite(组合)模式
- Command(命令)模式
- Observer(观察者)模式
- Template(模板)模式
- State(状态)模式
- Strategy(策略)模式
- MVC 模式
评论 (0)