ActionScript3.0教程:方法
方法是类定义中的函数。创建类的一个实例后,该实例就会捆绑一个方法。与在类外部声明的函数不同,不能将方法与附加方法的实例分开使用。
方法是使用 function 关键字定义的。与任何类属性一样,可以向方法应用任何类属性特性,包括 private、protected、public、internal、static 或自定义命名空间。您可以使用如下所示的函数语句:
public function sampleFunction():String {}
或者,也可以使用分配了函数表达式的变量,如下所示:
public var sampleFunction:Function = function () {}
多数情况下,您需要使用函数语句而不是函数表达式,原因如下:
-
函数语句更为简洁易读。
-
函数语句允许使用 override 和 final 关键字。
-
函数语句在标识符(即函数名)与方法体代码之间创建了更强的绑定。由于可以使用赋值语句更改变量值,可随时断开变量与其函数表达式之间的连接。虽然可通过使用 const(不是 var)声明变量来解决这个问题,但这种方法并不是最好的做法,因为这会使代码难以阅读,还会禁止使用 override 和 final 关键字。
必须使用函数表达式的一种情况是:选择将函数附加到原型对象时。
构造函数方法
构造函数方法有时简单称为构造函数,是与在其中定义函数的类共享同一名称的函数。只要使用 new 关键字创建了类实例,就会执行构造函数方法中包括的所有代码。例如,以下代码定义名为 Example 的简单类,该类包含名为 status 的属性。status 变量的初始值是在构造函数中设置的。
class Example { public var status:String; public function Example() { status = "initialized"; } } var myExample:Example = new Example(); trace(myExample.status); // output: initialized
构造函数方法只能是公共方法,但可以选择性地使用 public 属性。不能对构造函数使用任何其它访问控制说明符(包括使用 private、protected 或 internal)。也不能对函数构造方法使用用户定义的命名空间。
构造函数可以使用 super() 语句显式地调用其直接超类的构造函数。如果未显式调用超类构造函数,编译器会在构造函数体中的第一个语句前自动插入一个调用。还可以使用 super 前缀作为对超类的引用来调用超类的方法。如果决定在同一构造函数中使用 super() 和 super,务必先调用 super()。否则,super 引用的行为将会与预期不符。另外,super() 构造函数也应在 throw 或 return 语句之前调用。
下面的示例说明如果在调用 super() 构造函数之前尝试使用 super 引用,将会发生什么情况。新类 ExampleEx 扩展了 Example 类。ExampleEx 构造函数尝试访问在其超类中定义的状态变量,但访问是在调用 super() 之前进行的。ExampleEx 构造函数中的 trace() 语句生成了 null 值,原因是 status 变量在 super() 构造函数执行之前不可用。
class ExampleEx extends Example { public function ExampleEx() { trace(super.status); super(); } } var mySample:ExampleEx = new ExampleEx(); // output: null
虽然在构造函数中使用 return 语句是合法的,但是不允许返回值。换句话说,return 语句不得有相关的表达式或值。因此,不允许构造函数方法返回值,这意味着不可以指定任何返回值。
如果没有在类中定义构造函数方法,编译器将会为您自动创建一个空构造函数。如果某个类扩展了另一个类,编译器将会在所生成的构造函数中包括 super() 调用。
静态方法
静态方法也叫做类方法,它们是使用 static 关键字声明的方法。静态方法附加到类而不是类的实例,因此在封装对单个实例的状态以外的内容有影响的功能时,静态方法很有用。由于静态方法附加到整个类,所以只能通过类访问静态方法,而不能通过类实例访问。
静态方法为封装所提供的功能不仅仅在影响类实例状态的方面。换句话说,如果方法提供的功能对类实例的值没有直接的影响,该方法应是静态方法。例如,Date 类具有名为 parse() 的静态方法,它接收字符串并将其转换为数字。该方法就是静态方法,因为它并不影响类的单个实例。而 parse() 方法使用表示日期值的字符串,分析该字符串,然后使用与 Date 对象的内部表示形式兼容的格式返回一个数字。此方法不是实例方法,因为将该方法应用到 Date 类的实例并没有任何意义。
请将静态 parse() 方法与 Date 类的一个实例方法(如 getMonth())相比较。getMonth() 方法是一个实例方法,因为它通过检索 Date 实例的特定组件(即 month),对实例值直接执行操作。
由于静态方法不绑定到单个实例,因此不能在静态方法体中使用关键字 this 或 super。this 和 super 这两个引用只在实例方法上下文中有意义。
与其它基于类的编程语言不同,ActionScript 3.0 中的静态方法不是继承的。
实例方法
实例方法指的是不使用 static 关键字声明的方法。实例方法附加到类实例而不是整个类,在实现对类的各个实例有影响的功能时,实例方法很有用。例如,Array 类包含名为 sort() 的实例方法,该实例方法直接对 Array 实例执行操作。
在实例方法体中,静态变量和实例变量都在作用域中,这表示使用一个简单的标识符可以引用同一类中定义的变量。例如,以下类 CustomArray 扩展了 Array 类。CustomArray 类定义一个名为 arrayCountTotal 的静态变量(用于跟踪类实例总数)、一个名为 arrayNumber 实例变量(用于跟踪创建实例的顺序)和一个名为 getPosition() 的实例方法(用于返回这两个变量的值)。
public class CustomArray extends Array { public static var arrayCountTotal:int = 0; public var arrayNumber:int; public function CustomArray() { arrayNumber = ++arrayCountTotal; } public function getArrayPosition():String { return ("Array " + arrayNumber + " of " + arrayCountTotal); } }
虽然类外部的代码必须使用 CustomArray.arrayCountTotal 通过类对象来引用 arrayCountTotal 静态变量,但是位于 getPosition() 方法体中的代码可以直接引用静态 arrayCountTotal 变量。即使对于超类中的静态变量,这一点也适用。虽然在 ActionScript 3.0 中不继承静态属性,但是超类的静态属性在作用域中。例如,Array 类有几个静态变量,其中一个是名为 DESCENDING 的常量。位于 Array 子类中的代码可以使用一个简单的标识符来引用静态常量 DESCENDING。
public class CustomArray extends Array { public function testStatic():void { trace(DESCENDING); // output: 2 } }
实例方法体中的 this 引用的值是对方法所附加实例的引用。下面的代码说明 this 引用指向包含方法的实例:
class ThisTest { function thisValue():ThisTest { return this; } } var myTest:ThisTest = new ThisTest(); trace(myTest.thisValue() == myTest); // output: true
使用关键字 override 和 final 可以控制实例方法的继承。可以使用 override 属性重新定义继承的方法,以及使用 final 属性禁止子类覆盖方法。有关详细信息,请参阅覆盖方法。
get 和 set 存取器方法
get 和 set 存取器函数还分别称为 getter 和 setter,可以使用这些函数为创建的类提供易于使用的编程接口,并遵循信息隐藏和封装的编程原则。使用 get 和 set 函数可保持类的私有类属性,但允许类用户访问这些属性,就像他们在访问类变量而不是调用类方法。
这种方法的好处是,可避免出现具有不实用名称的传统存取器函数,如 getPropertyName() 和 setPropertyName()。getter 和 setter 的另一个好处是,使用它们可避免允许进行读写访问的每个属性有两个面向公共的函数。
下面的示例类名为 GetSet,其中包含名为 publicAccess() 的 get 和 set 存取器函数,用于提供对名为 privateProperty 的私有变量的访问:
class GetSet { private var privateProperty:String; public function get publicAccess():String { return privateProperty; } public function set publicAccess(setValue:String):void { privateProperty = setValue; } }
如果尝试直接访问属性 privateProperty,将会发生错误,如下所示:
var myGetSet:GetSet = new GetSet(); trace(myGetSet.privateProperty); // error occurs
GetSet 类的用户所使用的对象显示为名为 publicAccess 的属性,但实际上这是对名为 privateProperty 的 private 属性执行的一对 get 和 set 存取器函数。下面的示例将实例化 GetSet 类,然后使用名为 publicAccess 的公共存取器设置 privateProperty 的值:
var myGetSet:GetSet = new GetSet(); trace(myGetSet.publicAccess); // output: null myGetSet.publicAccess = "hello"; trace(myGetSet.publicAccess); // output: hello
使用 getter 和 setter 函数还可以覆盖从超类继承来的属性,这是使用常规类成员变量时不能做到的。在子类中不能覆盖使用 var 关键字声明的类成员变量。但是,使用 getter 和 setter 函数创建的属性没有此限制。可以对从超类继承的 getter 和 setter 函数使用 override 属性。
绑定方法
绑定方法有时也叫做闭包方法,就是从它的实例提取的方法。作为参数传递给函数的方法或作为值从函数返回的方法都是绑定方法。在 ActionScript 3.0 中,新增的绑定方法类似于闭包函数,其中保留了词汇环境,即使从其实例中提取出来也是如此。绑定方法与闭包函数之间的主要不同差别是,绑定函数的 this 引用保留到实现方法的实例的链接或绑定。换句话说,绑定方法中的 this 引用总是指向实现方法的原始对象。对于闭包函数,this 引用是通用的,这意味着调用函数时,该引用指向与函数关联的任何对象。
如果使用 this 关键字,了解绑定方法就很重要。重新调用 this 关键字可提供对方法父对象的引用。大多数 ActionScript 程序员都希望 this 关键字总是引用包含方法定义的对象或类。但是,如果不使用方法绑定,并不是总是做到这样。例如,在以前版本的 ActionScript 中,this 引用并不总是引用实现方法的实例。从 ActionScript 2.0 的实例中提取方法后,不但 this 引用不绑定到原始实例,而且实例类的成员变量和方法也不可用。在 ActionScript 3.0 中不存在这样的问题,这是因为将方法当作参数传递时会自动创建绑定方法。绑定方法用于确保 this 关键字总是引用在其中定义了方法的对象或类。
下面的代码定义了名为 ThisTest 的类,该类包含一个名为 foo() 的方法(该方法定义绑定方法)和一个名为 bar() 的方法(该方法返回绑定方法)。类外部的代码创建 ThisTest 类的实例,然后调用 bar() 方法,最后将返回值存储在名为 myFunc 的变量中。
class ThisTest { private var num:Number = 3; function foo():void // bound method defined { trace("foo's this: " + this); trace("num: " + num); } function bar():Function { return foo; // bound method returned } } var myTest:ThisTest = new ThisTest(); var myFunc:Function = myTest.bar(); trace(this); // output: [object global] myFunc(); /* output: foo's this: [object ThisTest] output: num: 3 */
代码的最后两行表明:虽然前一行中的 this 引用指向全局对象,但绑定方法 foo() 中的 this 引用仍然指向 ThisTest 类的实例。另外,存储在 myFunc 变量中的绑定方法仍然可以访问 ThisTest 类的成员变量。如果以上代码在 ActionScript 2.0 中运行,this 引用会匹配,但 num 变量将为 undefined。
绑定方法最值得注意的一种情况是使用事件处理函数,因为 addEventListener() 方法要求将函数或方法作为参数来传递。