关于变量和作用域
变量的作用域是指识别(定义)变量的区域和可以引用变量的区域。变量在其中被识别的区域可能在某个时间轴中或在某个函数内部,也可能在整个应用程序中是全局已知的。有关作用域的更多信息,请参见关于作用域和目标设定。
在使用 ActionScript 开发 Flash 应用程序时,了解变量作用域是非常重要的。作用域不仅表示可以在什么时间和位置引用变量,还表示一个特定的变量可以在应用程序中存在多长时间。在函数体中定义变量时,一旦指定的函数结束,变量就不再存在了。如果您试图在错误的作用域内引用对象或引用已过期的变量,您的 Flash 文档中将会出错,这将导致出现意外情况或使功能受到破坏。
在 ActionScript 中有三种类型的变量作用域:
a.全局变量和函数对于文档中的每个时间轴和作用域均可见。因此,全局变量是在代码的所有区域中定义的。
b.时间轴变量可用于该时间轴上的任何脚本。
c.本地变量在声明它们的函数体(由大括号界定)内可用。因此,本地变量仅是在代码的一部分中定义的。
全局变量
全局变量和函数对于您的文档中的每一时间轴和作用域而言都是可见的。要声明(或创建)具有全局作用域的变量,请在变量名前使用 _global 标识符,而不要使用 var = 语法。例如,以下代码创建全局变量 myName:
var _global.myName = "George"; // 全局变量的错误语法
_global.myName = "George"; // 全局变量的正确语法
但是,如果您使用与全局变量相同的名称初始化一个本地变量,则在处于该本地变量的作用域内时对该全局变量不具有访问权限,如下面的示例所示:
_global.counter = 100; // 声明全局变量
trace(counter); // 访问全局变量并显示 100
function count():Void {
for (var counter:Number = 0; counter <= 2; counter++) { // 本地变量
trace(counter); // 访问本地变量并显示 0 到 2
}
}
count();
trace(counter); // 访问全局变量并显示 100
此示例只是表明在 count() 函数作用域内未访问该全局变量。但是,如果加上一个 _global 前缀,您就可以访问具有全局作用域的变量了。例如,如果为 counter 加上前缀 _global,就可以访问它,如下面的代码所示:
trace(_global.counter);
您不能为在 _global 作用域中创建的值指定严格的数据类型,因为在指定数据类型时必须使用 var 关键字。例如,您不能执行以下操作:
_global.foo:String = "foo"; //语法错误
var _global.foo:String = "foo"; //语法错误
时间轴变量
时间轴变量可用于该特定时间轴上的任何脚本。要声明时间轴变量,请使用 var 语句并在该时间轴中的任一帧上初始化这些变量。该变量可以用于该帧和其后的所有帧,如下面的示例所示。
在文档中使用时间轴变量:
创建一个新的 Flash 文档并将它命名为 timelinevar.fla。
将下面的 ActionScript 添加到时间轴中的第 1 帧: var myNum:Number = 15; /* 在第 1 帧中初始化,这样它可用于所有帧 */
选择时间轴上的第 20 帧。
选择"插入">"时间轴">"空白关键帧"。
选择了新的关键帧之后,在"动作"面板中键入以下 ActionScript: trace(myNum);
选择"控制">"测试影片"对该新文档进行测试。
大约一秒钟之后,在"输出"面板中出现值 15。因为默认情况下 Flash 文档是循环播放的,所以每次播放头到达时间轴上的第 20 帧时,值 15 就会在"输出"面板中再次出现。要停止循环动作,请在 trace() 语句之后添加 stop();。
必须首先声明时间轴变量,然后再尝试在脚本中访问它。例如,如果将代码 var myNum:Number = 15; 放置在第 20 帧中,则附加到第 20 帧之前的任何帧上的脚本都无法访问 myNum,它们都是未定义的,而不包含值 15。
本地变量
在函数体内使用 var 语句时,声明的是本地变量。在函数块(又称函数定义)内声明一个本地变量时,该变量是在该函数块的作用域内定义的,因而在该函数块结束时会过期。因此,本地变量仅存在于该函数中。
例如,如果在名为 localScope 的函数中声明一个名为 myStr 的变量,该变量在该函数外部将不可用。
function localScope():Void {
var myStr:String = "local";
}
localScope();
trace(myStr); // Undefined,因为 myStr 不是在全局作用域内定义的
如果用于本地变量的变量名已经被声明为时间轴变量,则当本地变量在作用域内时,本地定义优先于时间轴定义。时间轴变量在该函数外部仍然存在。例如,下面的代码创建了一个名为 str1 的时间轴字符串变量,然后在 scopeTest() 函数中创建一个具有相同名称的本地变量。该函数中的 trace 语句生成该变量的本地定义,而函数外部的 trace 语句生成变量的时间轴定义。
var str1:String = "Timeline";
function scopeTest():Void {
var str1:String = "Local";
trace(str1); // 本地
}
scopeTest();
trace(str1); // 时间轴
在下一个示例中您可以看到,某些变量仅在特定函数的生命期内有效,如果尝试在该函数的作用域外引用该变量,就会生成错误。
在应用程序中使用本地变量:
创建一个新的 Flash 文档。
打开"动作"面板("窗口">"动作"),在时间轴的第 1 帧上添加下面的 ActionScript: function sayHello(nameStr:String):Void {
var greetingStr:String = "Hello, " + nameStr;
trace(greetingStr);
}
sayHello("world"); // Hello, world
trace(nameStr); // undefined
trace(greetingStr); // undefined
选择"控制">"测试影片"来测试该文档。
Flash 在"输出"面板中显示字符串"Hello, world",并显示 nameStr 和 greetingStr 的值为 undefined,因为这些变量在当前的作用域内不再可用。仅能在 sayHello 函数执行时引用 nameStr 和 greetingStr。函数退出后,这些变量将不再存在。
变量 i 和 j 经常用作循环计数器。在下面的示例中,将 i 用作本地变量;它只存在于 initArray() 函数的内部:
var myArr:Array = new Array();
function initArray(arrayLength:Number):Void {
var i:Number;
for(i = 0; i < arrayLength; i++) {
myArr
= i + 1;
}
}
trace(myArr); // <blank>
initArray(3);
trace(myArr); // 1,2,3
trace(i); // undefined
注意
下面的 for 循环语法也很常见:for (var i:Number = 0; i < arrayLength; i++) {...}。
因为变量 i 不是在主时间轴中定义的,所以此示例在 Flash 测试环境中显示 undefined。它仅存在于 initArray() 函数中。
可以使用本地变量防止出现名称冲突,名称冲突可能会导致应用程序出现意外结果。例如,如果将 age 用作本地变量,可以用它在一个上下文中存储一个人的年龄,而在另一个上下文中存储此人的孩子的年龄。因为是在不同的作用域中使用这些变量的,因此在这种情况下不会有冲突。
在函数体中使用本地变量是一个很好的习惯,这样该函数可以充当独立的代码。只能在本地变量的代码块中对它进行更改。如果函数中的表达式使用全局变量,则该函数外部的代码或事件也可以更改它的值,这样也更改了该函数。