类型检查

类型检查可以在编译时或运行时执行。静态类型语言(如 C++ 和 Java)在编译时执行类型检查。动态类型语言(如 Smalltalk 和 Python)在运行时执行类型检查。ActionScript 3.0 是动态类型的语言,它在运行时执行类型检查,同时也支持在名为“严格模式”的特殊编译器模式下在编译时执行类型检查。在严格模式下,类型检查既发生在编译时也发生在运行时,但是在标准模式下,类型检查仅发生在运行时。

在构造代码时,动态类型的语言带来了极大的灵活性,但代价是在运行时可能出现类型错误。静态类型的语言在编译时报告类型错误,但代价是要求类型信息在编译时是已知的。

子主题

编译时类型检查
运行时类型检查
is 运算符
as 运算符

编译时类型检查

在较大的项目中通常建议使用编译时类型检查,因为随着项目变大,相对于尽早捕获类型错误,数据类型的灵活性通常会变得不那么重要。这就是为什么将 Adobe Flash CS3 Professional 和 Adobe Flex Builder 2 中的 ActionScript 编译器默认设置为在严格模式下运行的原因。

为了提供编译时类型检查,编译器需要知道代码中的变量或表达式的数据类型信息。为了显式声明变量的数据类型,请在变量名后面添加后跟数据类型的冒号运算符 (:) 作为其后缀。要将数据类型与参数相关联,应使用后跟数据类型的冒号运算符。例如,下面的代码向 xParam 参数中添加数据类型信息,并用显式数据类型声明变量 myParam

function runtimeTest(xParam:String)
{
    trace(xParam);
}
var myParam:String = “hello”;
runtimeTest(myParam);

在严格模式下,ActionScript 编译器将类型不匹配报告为编译器错误。例如,下面的代码声明一个 Object 类型的函数参数 xParam,但是之后又尝试向该参数赋予 String 类型和 Number 类型的值。这在严格模式下会产生编译器错误。

function dynamicTest(xParam:Object)
{
    if (xParam is String)
    {
        var myStr:String = xParam; // 在严格模式下产生编译器错误
        trace("String: " + myStr);
    }
    else if (xParam is Number)
    {
        var myNum:Number = xParam; // 在严格模式下产生编译器错误
        trace("Number: " + myNum);
    }
}

但是,即使在严格模式下,也可以选择不在赋值语句右侧指定类型,从而退出编译时类型检查。可以通过省略类型注释或使用特殊的星号 (*) 类型注释,来将变量或表达式标记为无类型。例如,如果对上一个示例中的 xParam 参数进行修改,以便它不再有类型注释,则代码将在严格模式下进行编译:

function dynamicTest(xParam)
{
    if (xParam is String)
    {
        var myStr:String = xParam;
        trace("String: " + myStr);
    }
    else if (xParam is Number)
    {
        var myNum:Number = xParam;
        trace("Number: " + myNum);
    }
}
dynamicTest(100)            
dynamicTest("one hundred");

运行时类型检查

在 ActionScript 3.0 中,无论是在严格模式下还是在标准模式下编译,在运行时都将进行类型检查。请考虑以下情形:将值 3 作为一个参数传递给需要数组的函数。在严格模式下,编译器将生成一个错误,因为值 3 与 Array 数据类型不兼容。如果您禁用了严格模式而在标准模式下运行,则编译器将不会指出类型不匹配,但是当 Flash Player 在运行时进行类型检查时则会产生运行时错误。

下面的示例说明一个名为 typeTest() 的函数,该函数需要一个 Array 参数,但是接收到的是值 3。在标准模式下这会产生运行时错误,因为值 3 不是参数声明的数据类型 (Array) 的成员。

function typeTest(xParam:Array)
{
    trace(xParam);
}
var myNum:Number = 3;
typeTest(myNum); 
// 在 ActionScript 3.0 标准模式下出现运行时错误

还可能会出现如下情形:即使在严格模式下运行,也可能会获得运行时类型错误。如果您使用严格模式,但是通过使用无类型变量而退出了编译时类型检查,就可能会出现上述情形。当您使用无类型变量时,并不会消除类型检查,而只是将其延迟到运行时执行。例如,如果上一个示例中的 myNum 变量没有已声明的数据类型,那么,编译器将检测不到类型不匹配,但是 Flash Player 将生成一个运行时错误,因为它会将 myNum 的运行时值(赋值语句将其设置为 3)与 xParam 的类型(设置为 Array 数据类型)进行比较。

function typeTest(xParam:Array)
{
    trace(xParam);
}
var myNum = 3;
typeTest(myNum); 
// ActionScript 3.0 中的运行时错误

与编译时类型检查相比,运行时类型检查还允许更灵活地使用继承。标准模式会将类型检查延迟到运行时执行,从而允许您引用子类的属性,即使您“上传”也是如此。当您使用基类来声明类实例的类型,但是使用子类来实例化类实例时,就会发生上传。例如,您可以创建一个名为 ClassBase 的可扩展类(具有 final 属性的类不能扩展):

class ClassBase
{
}

随后,您可以创建一个名为 ClassExtender 的 ClassBase 子类,该子类具有一个名为 someString 的属性,如下所示:

class ClassExtender extends ClassBase
{
    var someString:String;
}

通过使用这两个类,可以创建一个使用 ClassBase 数据类型进行声明、但使用 ClassExtender 构造函数进行实例化的类实例。上传被视为安全操作,这是因为基类不包含子类中没有的任何属性或方法。

var myClass:ClassBase = new ClassExtender();

但是,子类中则包含其基类中没有的属性或方法。例如,ClassExtender 类中包含 someString 属性,该属性在 ClassBase 类中不存在。在 ActionScript 3.0 标准模式下,可以使用 myClass 实例来引用此属性,而不会生成编译时错误,如下面的示例所示:

var myClass:ClassBase = new ClassExtender();
myClass.someString = "hello";
// 在 ActionScript 3.0 标准模式下不出现错误

is 运算符

is 运算符是 ActionScript 3.0 中的新增运算符,它可用来测试变量或表达式是否为给定数据类型的成员。在早期的 ActionScript 版本中,此功能由 instanceof 运算符提供。但在 ActionScript 3.0 中,不应使用 instanceof 运算符来测试变量或表达式是否为数据类型的成员。对于手动类型检查,应用 is 运算符来代替 instanceof 运算符,因为表达式 x instanceof y 只是在 x 的原型链中检查 y 是否存在(在 ActionScript 3.0 中,原型链不能全面地描述继承层次结构)。

is 运算符检查正确的继承层次结构,不但可以用来检查对象是否为特定类的实例,而且还可以检查对象是否是用来实现特定接口的类的实例。下面的示例创建 Sprite 类的一个名为 mySprite 的实例,并使用 is 运算符来测试 mySprite 是否为 Sprite 和 DisplayObject 类的实例,以及它是否实现 IEventDispatcher 接口:

var mySprite:Sprite = new Sprite();
trace(mySprite is Sprite);                   // true
trace(mySprite is DisplayObject);            // true
trace(mySprite is IEventDispatcher);         // true

is 运算符检查继承层次结构,并正确地报告 mySprite 与 Sprite 和 DisplayObject 类兼容(Sprite 类是 DisplayObject 类的子类)。is 运算符还检查 mySprite 是否是从实现 IEventDispatcher 接口的任意类继承的。由于 Sprite 类是从实现 IEventDispatcher 接口的 EventDispatcher 类继承的,因此 is 运算符会正确地报告 mySprite 也实现该接口。

下面的示例说明与上一个示例相同的测试,但使用的是 instanceof 运算符,而不是 is 运算符。instanceof 运算符正确地识别出 mySprite 是 Sprite 或 DisplayObject 的实例,但是,当它用来测试 mySprite 是否实现 IEventDispatcher 接口时,返回的却是 false

trace(mySprite instanceof Sprite);           // true
trace(mySprite instanceof DisplayObject);    // true
trace(mySprite instanceof IEventDispatcher); // false

as 运算符

as 运算符是 ActionScript 3.0 中的新增运算符,也可用来检查表达式是否为给定数据类型的成员。但是,与 is 运算符不同的是,as 运算符不返回布尔值,而是返回表达式的值(代替 true)或 null(代替 false)。下面的示例说明了在简单情况下使用 as 运算符替代 is 运算符的结果,例如,检查 Sprite 实例是否为 DisplayObject、IEventDispatcher 和 Number 数据类型的成员。

var mySprite:Sprite = new Sprite();
trace(mySprite as Sprite);                 // [Sprite 对象]
trace(mySprite as DisplayObject);                 // [Sprite 对象]
trace(mySprite as IEventDispatcher);                 // [Sprite 对象]
trace(mySprite as Number);                                       // null

在使用 as 运算符时,右侧的操作数必须是数据类型。如果尝试使用表达式(而非数据类型)作为右侧的操作数,将会产生错误。


Flash CS3

 

评论添加到页面后给我发送电子邮件 | 评论报告

当前页: http://livedocs.adobe.com/flash/9.0_cn/main/00000045.html