ActionScript 2.0-AS1.0中的一点点面向对象编程 在我们转移到AS2之前先让我了解一下在AS1时的面向对象的编程。这一节对于在FLASH5和FLASHMX不太了解面向对编程的人来说很重要。如果你已经很了解这些可以直接跳过此节。 尽管AS1不是真正的面向对象的编程语言,开发人员已经在有些时候使用它进行面向对象的编程了。AS1中的任何东西都是依靠原型链也就是对象之间的联系。所以在AS1中使用面向对象需要了解原型链(或者是原型的关键字)。 AS1的类就象是规则的函数。方法附加在这个的类的原型上。例如: // Wizard class
function Wizard() { } // help()方法附加在WIZARD函数的原型上。 Wizard.prototype.help = function() { }; 如果我们把help()直接放在wizard class类中。FLASH在查找属性和方法时就不会找到它,因为FLASH在查找是沿着原型链进行搜索的。而在为所有的Wizard类创建一个实例copy.下面就是为每个实例创建的copy. function Wizard(){ this.help=function(){}}对于java,c#的程序员来说。这样的将方法代码放在类中会看来很熟悉,然而为了代码的可重用性我们还是应将方法附加在类的原型链上。 在下面的例子中假如我们针对一个类上有两个方法,一个是附加在原型链上,另一个是直接放在类中,flash将先获得内部方法。 // AS1_OOP_01.fla
function TestClass() { this.method = function() { trace("Internal method"); }; this.prop = ">>> Internal prop"; }// Attach a method to the prototype object of the class TestClass.prototype.method = function() { trace("Prototype method"); };TestClass.prototype.prop = ">>> Prototype prop";// Create an instance of the TestClass class var w = new TestClass();// Internal method is located before the prototype method w.method();// Replace the Internal method w.method = function() { trace("New method"); }; w.method();// Delete the Internal method delete w.method;// The only method remaining is the prototype method w.method();// Test the properties trace(w.prop);w.prop = ">>> New prop"; trace(w.prop);delete w.prop; trace(w.prop); 上面的例子的输出内容为: 从上面这个例子我们可以看出在使用AS1面向对向对于初学者来说是极易混淆的。其中知道将代码写在什么位是很重要的,因为它可能经常出现意想不到的结果,正如在商业上有一句流行的话是:但是等等,还有更多。。。。 ActionScript 2.0-AS2.0中的新特性 AS2中的新特性 AS2实际上不是一种新的语言,它是在AS1基础上的升级,如果你基本上掌握了AS1编程,那么学习它应是很容易的。接下来让我们看一下AS2所提供的新东西。 .严格的数据类型和编译提示。 .以数据类型为基础的代码提示。 .针对OOP的新的关键字和特性。 class、Interface、extends、implements、public、private、static、dynamic、intrinsic、import、class path、get、set 下面就让我看一下以上这些每一项都有什么新特点。 严格的数据类型 在比较专业编程语言中,表达是依靠数据类型的。它给我们的具大的好处是:它可以帮助编译器发现潜在的问题,获取类型不配的错误信息。它可以使你的代码清晰易读。 在AS1中声明一个变量如count的过程如下: var count;
在AS2中声明的过程应是这样。 var count:Number; 注意,它的语法结构是:<变量>:<数据类型>,这对许多java,c#,c++的程序员来说可能认为有些怪,这实际上是ECMA-262协会制定的规定,macromedia公司是按照这个规定做的而已。 AS2的变量,函数以及返回值都支持严格的数据类型,如下例函数接收字符串参数返回一个布尔值。 function func(arg:String):Boolean{};
当一个函数在没有接收到参数和返回任何值时,使有Void做为数据类型。 function func(arg:Void):Void{};
这种参数被写空的形式看起来有些怪,但这种用法却被大量的应用在组件的编写上,它只意味着当前没有指定的参数。然而如果你试着将参数传给这个函数,编译器在编译时是不会出现任何的错误提示同时也会将参数进行传递的。 尽管AS2支持严格的数据类型,却并没有被真正的执行这种语法,可是当编译器发现有数据类型不配的情况时就会出现错误提示信息,使用严格的数据来进行编程是一个好的开始习惯。它的好处我们在上面已经说过。如果你使用严格的数据类型来编程,那么你在发布时应指定使用AS2,并且指定发布为FLASH PLAYER 7。 使用严格的数据类型,新的编译器为你提供的了许多新的编译提示阻止你的影片出现类型不配的错误,但在编译过程中可能要花去较长的时间调试。 代码提示 在FALSHMX中的代码提示是依据变量名称的扩展如myPushButton_pb,mycomboBox_cb中的_pb,_cb来出现代码提示的,在2004中你会发现大多数的变量扩展不在生效,新版本的AS2以不同的约定型式来出现代码提示。 当一个变量类型被指定(如果这个变量类型对这个类是有效的)方法和属性的代码提示会在点的后面出现,否则是不会出现任何代码提示的。通过指定的数据类型来显示comboBox的代码提示如: var combo:mx.controls.comboBox;
combo. 你可以通过打开如下文件查看默认的扩展代码提示如: <Flash installation folder>\<language>\First
Run\ActionsPanel\AsCodeHints.xml
小提示:在2004中加入FLASHMX的代码提示 如果你使用2004来编辑你的FLASHMX文档,你可以将部分的FLASHMX代码提示加入到2004的代码提示中。 复制<Flash MX installation folder>\<language>\First Run\ActionsPanel\CustomActions\UIComponents.xml,中的 <codehints>
<typeinfo pattern="*_ch" object="FCheckBox"/> <typeinfo pattern="*_pb" object="FPushButton"/> <typeinfo pattern="*_rb" object="FRadioButton"/> <typeinfo pattern="*_lb" object="FListBox"/> <typeinfo pattern="*_sb" object="FScrollBar"/> <typeinfo pattern="*_cb" object="FComboBox"/> <typeinfo pattern="*_sp" object="FScrollPane"/> <typeinfo pattern="globalStyleFormat" object="FStyleFormat"/> </codehints> 这一段到Flash MX 2004's UIComponents.xml文件的结束标记之前,同样将这一段复制到2004的AsCodeHints.xml文件的<codehints></codehints> 之间注意多余的<codehints>标记要删除。 现在你就可以在2004中使用FLASHMX的组件代码提示了。 ActionScript 2.0-针对OOP的关键字和特性 下面我们将真正研究一下AS2的特性,在早期往往是在讨论AS1复杂的面向对象编程比实际工作更多一些,现在你将很快的看到,你不用花很多时间去争论怎么样做到最好的继承,将代码放置在哪和如何组织好你的代码库。 让我们先回顾一下OOP基础,OOP的最基本单元是对象,它包含两部分:代码和数据。由于对象是一种以自己自足的形式出现,因此它的数据和代码(方法)不需要公开。就象一个黑盒子,对象负责以自身的方法去管理自身的数据,对象与对象之间通过传递信息通讯。这些信息以公用或公开的方式传递和接收。而内部的数据和方法并没有直接参与其中,这就是OOP的基本原理。 在OOP的设计中,比做是一张大图,要想到重点和要实现的目标,以及各个部分之间的联系。将这张大图分成小的单元,并且保证各自的自身独立性,那么整个项目就很容易完成。而这些小的单元在OOP中就被称为类。所有这些AS2都提供了很好的支持。 下面这些关键字与OOP有关: class interface extends implements 我们不在重复mcromedia的帮助文档中对每一关键字的描述,我们可以用实例来说明。注意关键字intrinsic是mcromedia内部使用的关键字。这里面没package也就包的关键字,但是它与类路径的工作方式是很重要的,就象是其它语言中的包一样,如JAVA。 下面我们来看一下例子,在AS1中的类,将其改写为AS2的类。 // 构造函数
_global.Parent = function(name) { this.init.apply(this, arguments); }; // 类的属性 Parent.lastNames = new Array(); Parent.prototype.init = function(name) { this.lName = name; Parent.lastNames.push(name); this.id = Parent.lastNames.length-1; trace("Added ’"+ Parent.lastNames[this.id] +"’ at: "+ this.id); }; Parent.prototype.getLastName = function() { return (this.lName); }; Parent.prototype.setLastName = function(s) { this.lName = s; Parent.lastNames[this.id] = s; }; Parent.prototype.getNames = function() { return (Parent.lastNames); }; Parent.prototype.addProperty("lastName", Parent.prototype.getLastName, Parent.prototype.setLastName); Parent.prototype.addProperty("names", Parent.prototype.getNames, null); 上面的代码改写为AS2就向下面这样: 新的关键字被应用在如下的例子中:class, private, public, static, get, set class Parent {
private var lName:String = ""; private var id:Number; private static var lastNames:Array = new Array(); // 构造函数 public function Parent(name:String) { init.apply(this, arguments); } private function init(name:String):Void { lName = name; lastNames.push(name); id = lastNames.length-1; trace("Added ’"+ lastNames[id] +"’ at: " + id); } public function get lastName():String { return lName; } public function set lastName(s:String):Void { lName = s; lastNames[id] = s; } public function get names():Array { return lastNames; } } 通过上面的AS1和AS2执行同一个类。我们可以看出二者非常的相似,主要的不同以AS2为例: 1。以外部文件的形式存在如.as,同时注意类的名称要与外部文件名称相同。 ActionScript 2.0--THIS的范围 关键词THIS是可以任意使用的一个关键字,您可能也清楚它的使用,但是当一个局部变量和一个类的属性共用一个名称时。如果你要指定类的属性则必须要用this.下面的例子就说明这个问题。 1。新建一个FLASH文档,选择ActionScript文件,如下: 2。将你的文件另存在你在的工作目录中名为scopetest.as.就象我们之前提到过的一样,要将你的类名称和你的文件名保持一致。 3。输入如下代码: class ScopeTest {
private var myVar:String = "I am the class property!"; public function doTest(Void):Void { var myVar:String = "I am the local variable!"; trace ("myVar = " + myVar); trace ("this.myVar = " + this.myVar); } } 4。保存你的文件 var myTest:ScopeTest = new ScopeTest();
myTest.doTest(); 7。测试你影片 ActionScript 2.0--私有或保护 在AS2中需要注意的一件事是私有属性。就象JAVA一样,私有成员意味着只有类自身可以访问。而子类却不可以访问,包括是在同一个类路径或包内。就象其它语言一样私有属性多半是为了起到保护作用。 由于这种特性只在编译时才会生效,一件非常重要的事情是你必须确保编译器能正确的获得私有的方法和属性。因此注意对你的实例名使用严格的类型指定,如下我们声明一个属性为私有属性: class PrivateMemberClass{
private Var privateProp:String="I am a private property"; } 这个私有属性名为privatProp.当你的实例名没有用严格的数据类型指定时是可能被实例访问。 var instance=new PrivateMemberClass();
trace(instance.privateProp); 此时将会输出“I am a private property". 但是如果你使用的严格的数据类型指定就会出现编译错误。 如: var instance:PrivateMemberClass=new PrivateMemberClass();
trace(instance.privateProp); 此时就会出现编译错误。这是许多人常有错误,总会问为什么私有属性可以被实例访问,现在你知道了。 动态类允许动态的对类进行扩展(例如允许加入新的属性或方法)。象Jscript.NET程序中这种方式称为expando,如果类不是动态类(象Math类)用户不能加入新的属性和方法。而在as1中这其实是很平常的事。就象下面这样为MOVIECLIP加入新的属性和方法: movieClip.protoType.someNewMethed=function(){
一些方法; } 在as2中这种扩展方式是不允许的。然而我可能通过创建子类的方式加入新的属性和方法。 下面的例子是我们要扩展静态类Math中的Max()方法.我们要新将其扩展为在一些数中求出最大的数而不是原先那样只限定在两个数中求出最大的数。 dynamic class Math2 extends Math {
// store a reference to Math.max() private static var oMax:Function = Math.max; // static class cannot be instantiated private function Math2() {} // override Math.max(), support any number of arguments public static function max():Number { var a:Array = arguments; var n:Number = a.length; if (n > 2) { var m:Number = oMax(a[n-2],a[n-1]); // remove two elements from the end of the array; // could use ’a.length -= 2’ as a shortcut as well a.pop(); a.pop(); a.push(m); return Number(max.apply(null, a)); } else if (n == 2) { return oMax(a[0],a[1]); } else if (n == 1) { return a[0]; } else { return oMax(); } } } 不象原有的类那样,现在我们已经对其MAX()方法进行了扩展将其变成了动态类。并且形成了新的类名为math2. 现在可以试一下了。 trace(Math2.max(70,6,3,12,82,9,28,5)); ActionScript 2.0--继承 正如前面提到过的。继承对于OOP编程是很重要的尽管它不是绝对的需要。它用来定义子类与超类之间的关系。AS2为实现这一目的设置了一个新的关键词:extends.在上一例中的Math2中我们已经使用的了extends这一关键字继承Math类。它还是比较简单的。 在构造函数时首先应注意的是super()关建字。它的作用是调用超类的构造函数,如果你之前没有在超类中构造函数那么FLASH会自动生成一个空的构造函数。 值得欣慰的是许多BUG在新版的flash player7中已经被修复。但在FLASHPLAY6仍有bug的问题,如果你不太清楚,可能查看AS1中有关继承bug的相关列表文章。 如果你想要从子类传递参数给你的超类,你应确保在你的超类中已有了这些参数的声明。否则你会发现为什么只有部分的参数被传递。如我们要创建一个子类名为Child,它继承自他的父类。我们应在构造函数中这样写: class Child extends Parent { private var fName:String = ""; public function Child(lname:String, fname:String) { super(lname); // continue Child’s constructor code fName = fname; } } ActionScript 2.0--导入外部的类文件 为了更好的组织类和避免类名称的冲突.被许多语言应用的概念包被引入.ActionScript 2.0引入包就是为了解决这个问题. 类名称的冲突是指什么呢?我们假想有两个开发人员,每个人都建立了一个代码库.在库中都有一个名为utility的类.如果这两个代码库合在一起使用,这时就会造成flash的混乱,不知使用哪一个库中的类. 这时类路径及来出来挽救,通过将路径合并到类名称中.就象是硬盘中的文件一样,在不同的目录中可以有相同的文件存在.要指明引用哪一个类.要在导入过程中使用正确的类路径.如: import mx.events.Eventdesign;
一旦类被导入,我们在引用类时就可能只接使用类名称而不需要使用类的路径了. class MyBroadcaster {
public function MyBroadcaster() { EventDesign.initialize(this); } } 当然,你也可以不用导入的方式,而是在每次使用时都指明类的正确路径.可这样做会使人很烦的.当多次使用时要不断的输入重复的东西. class MyBroadcaster {
public function MyBroadcaster() { mx.events.EventDesign.initialize(this); } } 当在创建自已的类时,将你的类放在一个指定的项目目录中,或是放在一个公共的类库中,而不要将其放在 <Flash install folder>\<language>\First
Run\Classes\) 或<drive>:\Documents and Settings\<user>\Local
Settings\Application Data\Macromedia\Flash MX
2004\<language>\Configuration\Classes\).
这样做可以使执行同步同时减少编译时错误的出现.一种公用的方法是使用你的反面的域名作为类的路径如 import com.quantumwave.alliance.rebel.Commander;
如果要导入路径中的所有类.使用通配符*,如下: import com.quantumwave.*
这一步导入将导入com.quantumwave下的所有的类但在编译时只编译使用到的类,所以你不必担心导入所有的类会增大你文件的大小. ActionScript 2.0--接口 当在使用OOP时,除了继承比较重要之外,在就是接口了.就像JAVA和C#,ActionScript不提供多重继承(如一个子类可继承多个超类),这是因为如果使用不当在调试时就会象做了一场恶梦一样.会造成死循环和粘连不清的情况,在精心设计你的项目时,使用接口可以同样达到多重继承的效果,而不会出现上面说的那种很麻烦的情况. 一个接口就象是各类在执行方法时的一种协议,而通常在各个类未执行方法时是没有联系的.在接口中没有代码没有属性,只有方法,它的书写方式完全就象是在书写一个类一样,除了: 1.它们都没有属性 2.它们只有方法的标记,参数,类型和返回的类型 3.在方法定义的结尾只有小括号而没有大括号 下面是一个可拖动的类名为Dragable的范例(通常在命名接口时通常以大写的"I"开头). interface IDraggable {
public function startDrag():Void; public function stopDrag():Void; public function isDragging():Boolean; } 如果要使用Interface需要使用关键字implement.如下面的例子,child类继承超类同时使用接口IDraggable. class Child extends Parent implements IDraggable {
public function Child() { // add Child constructor code } public function startDrag():Void { // implement the code for startDrag(); } public function stopDrag():Void { // implement the code for stopDrag(); } public function isDragging():Boolean { // implement the code for isDragging(); } } 唯一在使用接口时注意的事情是,在类中应使用与接口中一样的方法,参数类型的定义,通过这种方式接口可以在两个不一样的程序员之间标准化代码,当一个已知的接口被类使用时,和序员只需知道接口以在不同的类中使用. |
|