Web

关于ActionScript

Flying
2013-06-06 / 0 评论 / 138 阅读 / 正在检测是否收录...

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 编程的开发人员提供健壮的模式。

  1. 语法方面的增强和改动
  • 引入了 package(包) 和 namespace(命名空间) 两个概念。其中 package 用来管理类定义,防止命名冲突,而 namespace 则用来控制程序属性方法的访问。
  • 新增内置类型 int(32 比特整数),uint(非负 32 比特整数),用来提速整数运算;
  • 新增 * 类型标识,用来标识类型不确定的变量,通常在运行时变量类型无法确定时使用。 在 ActionScript 2.0 中这种情况下需要用 Object 赖作为类型表识;
  • 新增 isas 两个运算符来进行类型检查。其中 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
  1. OOP 方面的增强

通过类定义而生成的实例,在 ActionScript 3.0 中是属于 Sealed 类型,即其属性和方法无法在运行时修改。这部分属性在 ActionScript 2.0 中是通过类的 prototype 对象来存储,而在 ActionScript 3.0 中则通过被称为 Trait 的概念对象存储管理,无法通过程序控制。这种处理方式一方面减少了通过 prototype 继承链查找属性方法所耗费的时间(所有父类的实现方法和属性都会被直接复制到对应的子类的 Trait 中),另一方面也减少了内存占用量,因为不用动态的给每一个实例创建 hhahtable 来存储变量。如果仍然希望使用 ActionScript 2.0 中类实例在运行时的动态特性,可以将类声明为 dynamic

  1. API 方面的增强
  • 新增 Display API, 使 ActionScript 3.0 可以控制包括 ShapeImageTextFieldSprite、MovieClipVideoSimpleButtonLoader 在内的大部分 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.* 包中。
  1. 与 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 程序。

  1. 新建工程。点选工具栏中的 New 按钮,从弹出的菜单中选择 ActionScript Project。如下图:

fb_menu.gif

在弹出的对话框中输入 HelloWorld 作为项目名称。单击下一步,主程序文件名默认下为 HelloWorld,输出文件夹名为 bin。我们不作更改,按 Finish 确定。如下图:

fb_project.gif

  1. 编写代码。打开 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 对象加载到容器中,这一点和旧版明显不同。

  1. 运行测试。按 Ctrl + S 保存文件,在 Navigation 视图中右键单击该文件,然后点击 run 按钮运行程序。如下图:

fb_run.gif

我们将在浏览器中看到 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 等脚本文件类似,主要有三种方式。

  1. 内联方式
    这种方式直接将 ActionScript 方法作为事件的属性值,当然这种方法一般只有一行,相对简单。如果要给方法传递对数,这种方法就不可取了。
  2. 级联方式
    这种方式将 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>
  1. 外联方式
// 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 中,新增了 intuint 简单数据类型。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 不同。

  1. 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); 
      } 
    } 
  } 
}
  1. 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 中新增了不少数组的方法,比如 indexOflastIndexOfeverysomemapforEach 等。看下面实例代码:

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 表示垂直轴。

  1. 确定两点之间的距离
// 定义 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);

看出来没?这就是勾股定理的一个简单应用。

  1. 按指定的角度和距离移动显示对象

    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 对象中还有 addsubtract 等其它方法,大家参看帮助文件吧。

使用 …(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(工厂)模式

as_factory.gif

  • Singleton(单例)模式

as_singleton.gif

  • Decorator(装饰)模式

as_decorator.gif

  • Adapter(适配器)模式

as_adapter.gif

  • Composite(组合)模式

as_composite.gif

  • Command(命令)模式

as_command.gif

  • Observer(观察者)模式

as_observer.gif

  • Template(模板)模式

as_template.gif

  • State(状态)模式

as_state.gif

  • Strategy(策略)模式

as_strategy.gif

  • MVC 模式

MVC模式

4

评论 (0)

取消