Navigation

Previous

Archives

2008年5月8日 @ 11:05

[Ebook]OReilly.Flex.3.Cookbook.May.2008

2008年3月11日 @ 08:17

Flex cookbook beta

2007年11月14日 @ 09:33

ActionScript 3.0 CookBook ascb 下载

2007年8月9日 @ 08:45

ActionScript 3 Cookbook 中文版

ActionScript 3 Cookbook 中文版 

本文未经同意,谢绝转载
转自:http://blog.csdn.net/lixinye0123/archive/2007/01/17/1485138.aspx

第一章. ActionScript 语言基础

第二章. 自定义类

2007年8月9日 @ 08:21

ActionScript 3 Cookbook 中文版 第四章.数字和数学

ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 1 页 共 23 页
第四章.数字和数学
4.0. 简介
4.1.数字的不同表现形式
4.2.不同数字类型之间的转换
4.3.四舍五入
4.4.格式化输出
4.5.不使用掩码进行数字格式化
4.6.格式化货币数字
4.7.生成随机数
4.8.模拟硬币投掷
4.9.模拟骰子
4.10.产生唯一的随机数
4.11.转换角度计算
4.12.计算两点之间的距离
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 2 页 共 23 页
4.0. 简介
数字的用法非常广泛,有多种表示形式,如十进制,十六进制,每种表示都有其特定用处,比如,
十六进制经常来表示 RGB 颜色值。(看4.2关于如何在各种表示法之间进行转换)。
数字和数学紧密相关,没有数学运算,Flash 将非常迟钝。像加法和减法等简单运算在ActionScript
经常用到,还有些运算,如随机数生成也是很常用的。
ActionScript 3.0 有三种基本数字类型: number, int, 和 uint。 number 对应浮点数, int 和 uint
对应整数。 int 和 uint 的区别就是uint 代表无符号整数。
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 3 页 共 23 页
4.1. 数字的不同表现形式
问题
我要指定数字为十进制,八进制或十六进制
解决办法
十六进制以0x开头,八进制以0开头,二进制不能直接表示,可以用等价的八进制或十六进制或用
parseInt( ) 函数转换字符为数字。
讨论
ActionScript 中各种格式使用是很方便的。比如,如果你要设置Sprite.rotation 属性,最好是用十
进制数:
rectangleSprite.rotation = 180;
另一方面,十六进制经常表示 RGB 颜色。例如,给 ColorTransform 对象的rgb 属性使用十六进
制数:
var pink:ColorTransform = new ColorTransform( );
pink.rgb = 0xF612AB;
0X 或0x开头的数字为十六进制数,十六进制有0到9和A 到F 字符组成,没有大小写之分。
0 开头的数字为八进制,有0 到7 组成;例如,0777 是个八进制数。大多数开发者不怎么使用八进
制,基本上都是使用十进制,除了颜色值用十六进制表示。
二进制只有0和1组成,虽然不能直接表示它,但你可以等效的十六进制来表示它,比如二进制1111
等于十六进制F,11111111 等于FF,二进制数在为操作(&, |, ^, >>, <<, >>>)上经常用。.
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 4 页 共 23 页
4.2. 不同数字类型之间的转换
问题
我要把当前数字类型转换为别的数字类型
解决办法
用parseInt( ) 函数把字符串转换为十进制数,用 Number, uint, 或 int 对象的 toString( ) 方法转换
为字符串。
讨论
在ActionScript 中不管你怎么设置数字,它的内部结果总是以十进制存贮:
// 创建颜色对象
var pink:ColorTransform = new ColorTransform( );
// 用十六进制设置 RGB
pink.rgb = 0xF612AB;
// 显示这个值时:16126635
trace(pink.rgb);
如果你要输出为其他表示法,用 toString( radix ) 方法
下面的例子用构造uint对象,输出不同的格式:
// radix 为 2, 输出二进制
trace(new uint(51).toString(2)); // 显示: 110011
// radix 为 16, 输出十六进制
trace(new uint(25).toString(16)); // 显示:19
var quantity:Number = 164;
trace(quantity.toString(16)); // 显示: a4
下面的例子设置ColorTransform 对象的RGB值,调用 toString( ) 以十六进制显示:
var pink:Color = new ColorTransform( );
pink.rgb = 0xF612AB;
trace(pink.rgb.toString(16)); // 显示:f612ab
toString( ) 方法的参数值的合法范围在2到36,如果没有指定参数值,默认为10。
和 toString( ) 相反的是 parseInt( ) 函数。它把指定的字符串转换为数字。
下面的代码把各种字符串,输出十进制数。
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 5 页 共 23 页
trace(parseInt("110011", 2)); // 显示: 51
trace(parseInt("19", 16)); // 显示: 25
trace(parseInt("17", 10)); // 显示: 17
如果不指定字符串进制,默认为十进制,除非在字符串前加上0x, 0X, 或0:
trace(parseInt("0x12")); // 显示: 18
trace(parseInt("017")); // 显示: 15
下面的例子给出的字符串格式和指定进制冲突,这时会默认为十进制
// 但是下面的字符串是不合法的数字,因此返回0
trace(parseInt("0x12", 10)); // 显示: 0
下面的字符串为八进制,但指定为十进制,因此系统默认字符串为十进制,而不是八进制。
trace(parseInt("017", 10)); // 显示 17
trace(parseInt("A9FC9C")); // NaN
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 6 页 共 23 页
4.3. 四舍五入
问题
我要进行四舍五入或取近似值.
解决办法
用 Math.round( ) 进行四舍五入, Math.floor( ) 和 Math.ceil( ) 进行上下近似值。
NumberUtilities.round( ) 方法可自定义取值。
讨论
很多情况我们需要得到整数部分而不是带有小数的浮点数。比如计算出结果为 3.9999999 ,期望
的结果应该是4.0。
Math.round( ) 方法进行四舍五入计算:
trace(Math.round(204.499)); // 显示: 204
trace(Math.round(401.5)); // 显示: 402
Math.floor( ) 方法去掉小数部分,Math.ceil( ) 方法去掉小数部分后自动加1:
trace(Math.floor(204.99)); // 显示: 204
trace(Math.ceil(401.01)); // 显示: 402
如果我想要把90.337 四舍五入到 90.34,可以这么写:
trace (Math.round(90.337 / .01) * .01); //显示: 9.34
trace (Math.round(92.5 / 5) * 5); // 显示: 95
trace (Math.round(92.5 / 10) * 10); // 显示: 90
更好的办法是用自定义函数NumberUtilities.round( ) ,它需要两个参数:
number :要舍入的数字
roundToInterval :间隔值
NumberUtilities 类在 ascb.util 包中。
imported ascb.util.NumberUtilities导入
trace(NumberUtilities.round(Math.PI)); // Displays: 3
trace(NumberUtilities.round(Math.PI, .01)); // Displays: 3.14
trace(NumberUtilities.round(Math.PI, .0001)); // Displays: 3.1416
trace(NumberUtilities.round(123.456, 1)); // Displays: 123
trace(NumberUtilities.round(123.456, 6)); // Displays: 126
trace(NumberUtilities.round(123.456, .01)); // Displays: 123.46
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 7 页 共 23 页
4.4. 格式化输出
问题
我要把数字进行格式化输出
解决办法
用 NumberFormat 类,设置掩码,然后调用 format( ) 方法。
讨论
经常会遇到需要在输出时在头部和尾部加0或空格来达到格式化输出的目的,比如显示时间或日期。
比如要格式化输出6 小时3 分钟,显示为 6:03 或 06:03,而不是 6:3。而且还经常碰到输出时进
行对齐等,这都需要进行格式化输出:
123456789
1234567
12345
虽然自己都可以做到这种效果,但是你会发现用 NumberFormat 对象更简单更灵活。
NumberFormat 类是个自定义类,可到http://www.rightactionscript.com/ascb 下载。使用它须先导
入:import ascb.util.NumberFormat:
接下来决定是什么掩码进行格式化,它可以是0,#,.,,,或者其他。
零 (0)
使用零作为占位符
井号 (#)
点号(.)
逗号 (,)
下面看一下例子:掩码如下:
##,###.0000
格式化如下数字:1.2345, 12.345, 123.45, 1234.5, 和 12345, 结果:
1.2345
12.3450
123.4500
1,234.5000
12,345.0000
通过构造函数直接传入参数作为掩码:
var styler:NumberFormat = new NumberFormat("##,###.0000");
另外,使用属性进行修改掩码:
styler.mask = "##.00";
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 8 页 共 23 页
设置好掩码,调用 format( ) 方法就可以格式化数字了:
trace(styler.format(12345);
var styler:NumberFormat = new NumberFormat("#,###,###,###");
trace(styler.format(1));
trace(styler.format(12));
trace(styler.format(123));
trace(styler.format(1234));
styler.mask = "#,###,###,###.0000";
trace(styler.format(12345));
trace(styler.format(123456));
trace(styler.format(1234567));
trace(styler.format(12345678));
trace(styler.format(123456789));
输出如下:
1
12
123
1,234
12,345.0000
123,456.0000
1,234,567.0000
12,345,678.0000
123,456,789.0000
NumberFormat 对象自动本地化返回值。如果Flash播放器在英文操作系统上运行, NumberFormat
类是用逗号和点号,如果在法语操作系统上运行,正好相反,使用点号和逗号,因此需要覆盖自动
本地化:
有几种方法覆盖自动本地化设置:
把Locale 对象作为format( ) 方法的第二个参数,format( ) 方法根据Locale 对象的设置进行格式
化。Locale 对象使用两个参数,第一个是语言代码,如en,第二个参数为国家代码,如EN.
通过全局设置Locale.slanguage 或 Locale.svariant 属性就不需要给format( ) 方法传递参数了
使用符号对象作为format( )的第二个参数,包括两个属性:group 和decimal。该方法适合没有用
Locale对象进行全局设置下使用。
Locale 类在 ascb.util 包中,使用前导入。
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 9 页 共 23 页
下面的代码展示了三种方法:
var styler:NumberFormat = new NumberFormat("#,###,###,###.00");
Locale.slanguage = "fr";
trace(styler.format(1234));
trace(styler.format(12345, {group: ",", decimal: "."}));
trace(styler.format(123456));
Locale.slanguage = "en";
trace(styler.format(1234567));
trace(styler.format(12345678, new Locale("es", "ES")));
trace(styler.format(123456789, {group: "|", decimal: ","}));
结果:
1.234,00
12,345.00
123.456,00
1,234,567.00
12.345.678,00
123|456|789,00
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 10 页 共 23 页
4.5. 不使用掩码进行数字格式化
问题
我不想使用掩码进行格式化
解决办法
用 NumberFormat 对象不设置掩码,调用 format( ) 方法
讨论
4.4 节讨论了各种复杂的数字格式化方法,但是能不能不用那么复杂呢,NumberFormat 类提供了
一个简单的办法,只使用最简单的format( )方法:
var styler:NumberFormat = new NumberFormat( );
trace(styler.format(12.3));
trace(styler.format(123.4));
trace(styler.format(1234.5));
trace(styler.format(12345.6));
显示如下:
12.3
123.4
1,234.5
12,345.6
正像上一节所说的,仍然有本地化问题,本地化处理和上一节一样:
var styler:NumberFormat = new NumberFormat( );
Locale.slanguage = "fr";
trace(styler.format(1234, new Locale("en")));
trace(styler.format(12345, {group: ":", decimal: "|"}));
trace(styler.format(123456));
输出:
1,234
12:345
123.456
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 11 页 共 23 页
4.6. 格式化货币数字
问题
我要格式化货币,比如美元
解决办法
使用 NumberFormat.currencyFormat( ) 方法
讨论
不像其他语言,比如ColdFusion,ActionScript 没有提供内建的函数格式化货币数字。自定义类
NumberFormat 包括一个currencyFormat( )方法。
currencyFormat( ) 至少需要一个参数,看下面的简单代码:
var styler:NumberFormat = new NumberFormat( );
trace(styler.currencyFormat(123456));
在英文操作系统上运行结果如下:
$123,456.00
和 format( ) 方法类似,currencyFormat( ) 方法根据自动本地化设置进行格式化。因此,如果上面
的代码在西班牙语操作系统上运行结果如下:
123.456,00
覆盖自动本地化方法和format()类似:
使用 Locale 对象作为currencyFormat( )的第二个参数.
赋全局变量给 Locale.slanguage 和 Locale.svariant 属性
使用字符对象作为currencyFormat( )的第二个参数.
currencyFormat( ) 的字符对象比format( ) 方法中稍微不一样,它包括4个属性: group, decimal,
currency, 和 before。group 和 decimal 属性和 format( ) 方法一样。currency 属性为货币符号,
before 为布尔值,表示货币符号的位置。
下面是currencyFormat( )的一些例子代码:
var styler:NumberFormat = new NumberFormat( );
trace(styler.currencyFormat(123456));
Locale.slanguage = "nl";
trace(styler.currencyFormat(123456));
trace(styler.currencyFormat(123456, new Locale("sv")));
trace(styler.currencyFormat(123456, {group: ",", decimal: ".", currency: "@", before: false}));
输出结果:
$123,456.00
123.456,00
123,456.00kr
123,456.00@
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 12 页 共 23 页
4.7. 生成随机数
问题
我要生成随机数
解决办法
使用Math.random( ) 方法生成 0 到 .999999的随机数。还有,是用NumberUtilities.random( ) 方
法可以生成指定范围的随机数
讨论
Math.random( ) 方法产生 0 到 0.999999999的浮点随机数。大多数情况我们希望产生整数而不是
浮点数,还好随机值可以指定精度。
NumberUtilities.random( ) 方法产生指定的范围和精度,它接受三个参数:
minimum
可接受的最小值
maximum
可接受的最大值
roundToInterval
间隔值,可选
NumberUtilities 类在 ascb.util 包中,使用前导入。
例子如下:
// 产生 0 到 100的整数.
trace(NumberUtilities.random(0, 100));
// 产生 0 到 100的整数,间隔为5
trace(NumberUtilities.random(0, 100, 5));
trace(NumberUtilities.random(-10, 10, .1));
trace(NumberUtilities.random(-1, 1, .05));
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 13 页 共 23 页
package {
import flash.display.Sprite;
import ascb.util.NumberUtilities;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class RandomNumberTest extends Sprite {
private var _total:uint;
private var _numbers:Object
public function RandomNumberTest( ) {
var timer:Timer = new Timer(10);
timer.addEventListener(TimerEvent.TIMER, randomizer);
timer.start( );
_total = 0;
_numbers = new Object( );
}
private function randomizer(event:TimerEvent):void {
var randomNumber:Number = NumberUtilities.random(1, 10, 1);
_total++;
if(_numbers[randomNumber] == undefined) {
_numbers[randomNumber] = 0;
}
_numbers[randomNumber]++;
trace("random number: " + randomNumber);
var item:String;
for(item in _numbers) {
trace("\t" + item + ": " + Math.round(100 * _numbers[item]/_total));
}
}
}
}
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 14 页 共 23 页
4.8. 模拟硬币投掷
问题
我要模拟硬币投掷或布尔事件来达到50%几率成功。
解决办法
用NumberUtilities.random( ) 方法产生 0 到 1的整数,根据每种可能得出结果。
讨论
用 random( ) 方法产生指定范围的随机整数,能够产生两个结果对应硬币的正面和反面状态,在程
序里我们用0 代表一个状态,1代表另一状态,当然你用1 和2也是可以的,总之是2 个状态,这
样就能模拟硬币投掷了:
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.MouseEvent;
import ascb.util.NumberUtilities;
public class CoinExample extends Sprite {
private var _field:TextField;
public function CoinExample( ) {
_field = new TextField( );
_field.autoSize = "left";
addChild(_field);
var circle:Sprite = new Sprite( );
circle.graphics.beginFill(0, 100);
circle.graphics.drawCircle(100, 100, 100);
circle.graphics.endFill( );
circle.addEventListener(MouseEvent.CLICK, onClick);
addChild(circle);
}
private function onClick(event:MouseEvent):void {
var randomNumber:Number = NumberUtilities.random(0, 1);
_field.text = (randomNumber == 0) ? "heads" : "tails";
}
}
}
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 15 页 共 23 页
记录正反面出现次数:
package {
import flash.display.Sprite;
import flash.text.TextField;
import ascb.util.NumberUtilities;
public class CoinTest extends Sprite {
private var _field:TextField;
public function CoinTest( ) {
_field = new TextField( );
_field.autoSize = "left";
addChild(_field);
var heads:Number = 0;
var tails:Number = 0;
var randomNumber:Number;
for(var i:Number = 0; i < 10000; i++) {
randomNumber = NumberUtilities.random(0, 1);
if(randomNumber == 0) {
heads++;
}
else {
tails++;
}
}
_field.text = "heads: " + heads + ", tails: " + tails;
}
}
}
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 16 页 共 23 页
如果要测试随机数,应该保存在变量中,像上面的代码,下面代码的统计是错误的,因此else if 每
次都产生新的随机数:
package {
import flash.display.Sprite;
import ascb.util.NumberUtilities;
public class RandomLetter extends Sprite {
public function RandomLetter( ) {
for(var i:Number = 0; i < 10000; i++) {
trace(getRandomLetter( ));
}
}
private function getRandomLetter( ):String {
if(NumberUtilities.random(0, 2) == 0) {
return "A";
}
else if(NumberUtilities.random(0, 2) == 1) {
return "B";
}
else if(NumberUtilities.random(0, 2) == 2) {
return "C";
}
// It's possible that none of the preceding will evaluate to true,
// and the method will reach this point without returning a valid
// string.
return "";
}
}
}
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 17 页 共 23 页
下面才正确:
package {
import flash.display.Sprite;
import ascb.util.NumberUtilities;
public class RandomLetter extends Sprite {
public function RandomLetter( ) {
for(var i:uint = 0; i < 10000; i++) {
trace(getRandomLetter( ));
}
}
private function getRandomLetter( ):String {
// random( ) 返回结果到变量上
var randomInteger:uint = NumberUtilities.random(0, 2);
if(randomInteger == 0) {
return "A";
}
else if(randomInteger == 1) {
return "B";
}
else if(randomInteger == 2) {
return "C";
}
return "";
}
}
}
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 18 页 共 23 页
4.9. 模拟骰子
问题
我要模仿掷骰子
解决办法
用NumberUtilities.random( ) 方法产生指定范围的随机数
讨论
用 random( ) 方法产生整数来模拟掷骰子,这在很多游戏中经常用到,这次我们在ActionScript中
实现
一般我们产生随机数然后保存它在使用,如果要重新使用存在的随机数,应保存它而不是再产生新
的随机数。注意下面两种情况,第一种,dice 总是die1和die2的之和:
var die1:uint = NumberUtilities.random(1, 6);
var die2:uint = NumberUtilities.random(1, 6);
var dice:uint = die1 + die2;
下面的情况,dice和die1 和die2 没有关系,换句话说,即使die1和die2加起来等于7,dice也不
会等于它:
var die1:uint = NumberUtilities.random(1, 6);
var die2:uint = NumberUtilities.random(1, 6);
var dice:uint = NumberUtilities.random(1, 6) + NumberUtilities.random(1, 6);
NumberUtilities.random( ) 还可以模拟多边的骰子:
var die1:uint = NumberUtilities.random(1, 15);
下面的例子模拟了一个骰子
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 19 页 共 23 页
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.MouseEvent;
import ascb.util.NumberUtilities;
public class NumbersAndMath extends Sprite {
var _die:Sprite;
var _value:uint;
public function NumbersAndMath( ) {
_die = new Sprite( );
addChild(_die);
_die.addEventListener(MouseEvent.CLICK, rollDie);
rollDie(null);
}
private function rollDie(event:MouseEvent):void {
_value = NumberUtilities.random(1, 6);
_die.graphics.clear( );
_die.graphics.lineStyle( );
_die.graphics.beginFill(0xFFFFFF);
_die.graphics.drawRect(0, 0, 50, 50);
_die.graphics.endFill( );
_die.graphics.beginFill(0x000000);
if(_value == 1 || _value == 3 || _value == 5) {
_die.graphics.drawCircle(25, 25, 4);
}
if(_value == 2 || _value == 3 || _value == 4 ||
_value == 5 || _value == 6)
{
_die.graphics.drawCircle(11, 11, 4);
_die.graphics.drawCircle(39, 39, 4);
}
if(_value == 4 || _value == 5 || _value == 6) {
_die.graphics.drawCircle(11, 39, 4);
_die.graphics.drawCircle(39, 11, 4);
}
if(_value == 6) {
_die.graphics.drawCircle(11, 25, 4);
_die.graphics.drawCircle(39, 25, 4);
}
}
}
}
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 20 页 共 23 页
4.10. 产生唯一的随机数
问题
我要产生唯一数
解决办法
使用 NumberUtilities.getUnique( ) 方法
讨论
唯一随机数经常在产生唯一的URL 时用到。就是在URL后加上个唯一的数字,以区别于使用过的
URL,因此浏览器总是会去调用远程服务器而不是访问缓存
NumberUtilities.getUnique( ) 返回基于毫秒的数字
trace(NumberUtilities.getUnique( ));
下面的代码产生一组唯一的随机数:
for(var i:Number = 0; i < 100; i++) {
trace(NumberUtilities.getUnique( ));
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 21 页 共 23 页
4.11. 转换角度计算
问题
我要计算角度及转换为合适的单位
解决办法
使用 Unit 和 Converter 类
讨论
影片剪辑的_rotation 属性使用角度计算的。如果用弧度而不是角度就有些麻烦了。首先要把弧度值
转换为角度值,再赋值给 _rotation 属性,而且,大多数人喜欢用角度计算。还好,把弧度转换为
角度挺容易,只要180/Math.PI.,角度转换为弧度就反一下,Math.PI/180. ,而且使用自定义的Unit
和Converter 类更简单。
这两个类都是自定义类,在ascb.unit 包中,首先创建Unit 实例,然后描述需要转换的单位类型,
Unit.DEGREE, Unit.RADIAN, 和 Unit.GRADIAN 常量返回新的Unit 对象表示各种单位。Unit 对
象有些属性,包括name, category, label, 和labelPlural:
var degree:Unit = Unit.DEGREE;
trace(degree.name); // 显示: degree
trace(degree.category); // 显示: angle
trace(degree.label); // 显示: degree
trace(degree.labelPlural); // 显示: degrees
使用getConverterTo( ) 方法,传递 Unit 对象作为,得到converter 对象,看下面的代码得到弧度
向角度转换的对象:
var converter:Converter = Unit.DEGREE.getConverterTo(Unit.RADIAN);
一旦得到Converter 实例,运行convert( ) 方法,指定值进行转换:
trace(converter.convert(90));
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 22 页 共 23 页
convertWithLabel( ) 方法输出字符串:
var converterToRadians:Converter = Unit.DEGREE.getConverterTo(Unit.RADIAN);
var converterToDegrees:Converter = Unit.RADIAN.getConverterTo(Unit.DEGREE);
trace(converterToRadians.convertWithLabel(1));
trace(converterToRadians.convertWithLabel(57.2957795130823));
trace(converterToDegrees.convertWithLabel(1));
trace(converterToDegrees.convertWithLabel(0.0174532925199433));
/*
显示:
0.0174532925199433 radians
1 radian
57.2957795130823 degrees
1 degree
*/
如果执行相反操作,使用getConverterFrom( ) 方法:
var converter:Converter = Unit.DEGREE.getConverterFrom(Unit.GRADIAN);
trace(converter.convert(100));
trace(converter.convert(23));
ActionScript 3 Cookbook 中文版
第四章.数字和数学
第 23 页 共 23 页
4.12. 计算两点之间的距离
问题
我要计算两点之间的距离
解决办法
根据勾股定理,使用 Math.pow( ) 和 Math.sqrt( ) 联合计算
讨论
通过勾股定理可以计算出两点之间的距离(直线)。一个三角形,最长边的平方等于其他两边的平方
和:
a2 + b2 = c2
根据这个公式可以计算出两点之间的距离,a 是两点X坐标的差值,b 是两点Y坐标的差值:
var c:Number = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));

2007年8月9日 @ 08:20

ActionScript 3 Cookbook 中文版 第三章. 运行时环境

ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 1 页 共 17 页
第三章. 运行时环境
3.0.简介
3.1.检测播放器版本
3.2.检测操作系统
3.3.检测播放器类型
3.4.检测系统语言
3.5.检测显示设置
3.6.缩放影片
3.7.改变对齐方式
3.8.隐藏Flash播放器的菜单项
3.9.检测设备音频
3.10.检测设备视频
3.11.提示用户改变播放器设置
3.12.处理系统安全
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 2 页 共 17 页
3.0. 简介
Flash Player 9 关于控制运行时环境提供了更多的信。The flash.system.Capabilities 类有许多静态
方法返回关于播放器和计算机的信息,比如操作系统,语言,音频和视频。还有其他的类如
flash.display.Stage 和 flash.system.Security 控制其他一些元素如播放器右键菜单和设置对话框。
flash.display.Stage 类也控制影片剪辑缩放和对齐。
Flash Player 9 可能是自 Flash Player 7 之后最具重要意义的一次升级。它比以往提供了更多能力
控制上下文菜单。在Flash Player 7里,用 ContextMenu 类,可以控制右键菜单,可以添加或删
除菜单项。
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 3 页 共 17 页
3.1. 检测播放器版本
问题
我要确定客户机上的Flash播放器版本
解决办法
可以使用Flash Player 检测工具。
(http://www.adobe.com/software/flashplayer/download/detection_kit).
讨论
检测客户机上的Flash版本是个多年以来的难题,有各种开发者提供的方法,一般有三种方法:
基于浏览器脚本检测
服务端检测
ActionScript 检测
第一种方法使用JavaScript 或 VBScript 检测Flash 播放器版本。但是很多脚本在不同的平台不同
的浏览器上会有兼容性问题出现。
服务端检测也有局限性,如果你无权限创建服务端脚本,这就很困难了。
大多基于 ActionScript 的检测技术不能在ActionScript 3.0 上用了。 ActionScript 3.0 有一套自己
的检测客户端版本的方法,那就是 flash.system.Capabilities.version 属性。但是它不能检测Flash
Player 8.5 之前的版本。
还好Adobe 已经考虑到所有这些问题,推出了 Flash Player Detection Kit 来指导你用最好的办法
检测播放器版本。
检测包里包含文档和各种解决办法,包括VBScript 和 JavaScript 例子;ActionScript 检测;还有
服务端的 ColdFusion 和 PHP 脚本检测。
基于ActionScript 的检测是比较好的,它可以支持到Flash 播放器4,它使用一个 Flash 4 .swf t
来检测当前版本,你所要做的就是在脚本里设置最小的版本变量,如果当前版本高,它会调用指定
的内容。
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 4 页 共 17 页
3.2. 检测操作系统
问题
我要知道客户端的操作系统。
解决办法
使用flash.system.Capabilities.os 属性
讨论
ActionScript 3.0中,flash.system.Capabilities.os 属性返回操作系统名称和版本字符串。值可能包
括Windows XP, Windows 2000, Windows NT, Windows 98/Me, Windows 95, 和 Windows CE. 在
苹果机上,字符串包括版本号,比如 Mac OS 9.2.1 或 Mac OS X 10.4.4.
你可能基于操作系统做一些特殊处理,比如,根据当前系统载入特定的图标,或只是记录下用户的
操作系统来统计。
下面的代码展示检测操作系统:
var os:String = System.capabilities.os.substr(0, 3);
if (os == "Win") {
// Windows-specific code goes here
} else if (os == "Mac") {
// Mac-specific code goes here
} else {
// Must be Unix or Linux
}
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 5 页 共 17 页
3.3. 检测播放器类型
问题
我想知道播放器类型You want to know what type of Flash Player the .swf is being run from.
解决办法
使用 flash.system.Capabilities.playerType 属性.
讨论
播放器的类型有:
浏览器插件形式存在于 Mozilla 或 Firefox
ActiveX 控件形式存在于Internet Explorer
独立播放器
外部播放器,它与Flash IDE 进行交互。
这些都是.swf 运行的环境,如果你要使用脚本进行交互,这就需要知道应用程序到底在Internet
Explorer 或其他的浏览器运行。如果在独立播放器里运行,那么JavaScript等脚本就不管用了。
检测播放器类型,察看flash.system.Capabilities.playerType 的值。
它可能是PlugIn, ActiveX, StandAlone, 和 External:
if(flash.system.Capabilities.playerType == "Plugin") {
// do actions for Mozilla, etc. browsers
}
else if(flash.system.Capabilities.playerType == "ActiveX") {
// do actions for IE
}
else {
// do actions for no browser
}
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 6 页 共 17 页
3.4. 检测系统语言
问题
我想知道客户端系统使用什么语言和输入法
解决办法
使用 flash.system.Capabilities.language 属性和 flash.system.IME 类
讨论
flash.system.Capabilities.language 属性给出客户端系统的语言,返回两个 ISO-639-1 字符(如
"fr" 代表 French). 有些国家代码两个字符是不合适的,比如( "zh-CN" 代表 Simplified Chinese 和
"zh-TW" 代表 Traditional Chinese).
下面的代码展示如何使用语言属性:
// Example output: en-US
trace(flash.system.Capabilities.language);
var greetings:Array = new Array( );
greetings["en"] = "Hello";
greetings["es"] = "Hola";
greetings["fr"] = "Bonjour";
var lang:String = flash.system.Capabilities.language.substr(0, 2);
if (greetings[lang] == undefined) {
lang = "en";
}
trace(greetings[lang]);
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 7 页 共 17 页
如果要创建国际化的Flash,可以把文本保存在数组里,根据语言动态显示,或者直接做成多个Flash
版本(每个语言一个),如 myMovie_en.swf, myMovie_es.swf, myMovie_fr.swf, 等.
//从 capabilities 对象上得到语言值
var lang:String = System.capabilities.language.substr(0, 2);
// 创建支持语言数组
var supportedLanguages:Array = ["en", "es", "fr"];
// 设置默认语言.
var useLang:String = "en";
//循环匹配,如果找到,设置 useLang
for (var i:int = 0; i < supportedLanguages.length; i++) {
if (supportedLanguages[i] == lang) {
useLang = lang;
break;
}
}
// 载入对应Flash
var movieURL:String = "myMovie_" + useLang + ".swf");
还有一点也很重要,比如用户使用的输入语言,比如中文,日文,韩文,输入这些字符需要输入法,
这时特定操作系统的一部分。
flash.system.Capabilities.hasIME 返回用户是否使用输入法. flash.system.IME 类返回关于输入法
的信息。flash.system.IME.enabled 属性设置用户是否可以使用输入法。在有些操作系统和版本上
你可以发送字符串给IME来转换成正确的字符,接受IME 的返回,但这不是所有操作系统都支持的,
最好检测下先。
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 8 页 共 17 页
3.5. 检测显示设置
问题
我要知道客户机的显示设置情况
解决办法
使用 system.capabilities 对象的 screenResolutionX 和 screenResolutionY 属性
讨论
screenResolutionX 和 screenResolutionY 属性返回桌面的显示分辨率:
trace(flash.system.Capabilities.screenResolutionX);
trace(flash.system.Capabilities.screenResolutionY);
// 1024
// 768
有了这些值,你可以决定怎样显示flash影片。这一点对于Flash播放器也是很重要的,例如,手机
屏幕和电脑屏幕尺寸是不同的,因此你要根据情况载入不同的尺寸的内容。
var resX:int = flash.system.Capabilities.screenResolutionX;
var resY:int = flash.system.Capabilities.screenResolutionY;
if ( (resX <= 240) && (resY <= 320) ) {
var url:String = "main_pocketPC.swf";
}
else {
var url:String = "main_desktop.swf";
}
loader.load(new URLRequest(url));
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 9 页 共 17 页
利用分辨率还可以居中你的弹出窗口:
var resX:int = flash.system.Capabilities.screenResolutionX;
var resY:int = flash.system.Capabilities.screenResolutionY;
//设置窗口的宽和高
var winW:int = 200;
var winH:int = 200;
// 设置窗口起始坐标
var winX:int = (resX / 2) - (winW / 2);
var winY:int = (resY / 2) - (winH / 2);
// 创建代码,然后传递给 URLLoader.load( )
// 打开新浏览器窗口
var jsCode:String = "javascript:void(
newWin=window.open('http://www.person13.com/'," +
"'newWindow', 'width=" + winW +
", height=" + winH + "," +
"left=" + winX + ",top=" + winY + "'));";
// 使用 URLLoader 对象调用 JavaScript 函数
urlLoader.load(new URLRequest(jsCode));
另外,得到屏幕分辨率可以确定是否缩放Flash 影片。例如,用户把屏幕分辨率调高了,这时字体
就变得小了。
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 10 页 共 17 页
3.6. 缩放影片
问题
我想让影片适应屏幕大小
解决办法
使用 stage.scaleMode 属性
讨论
这里有几种缩放模式:exactFit, noBorder, noScale, 和 showAll。为了避免编写上错误,这些字符
串都成为了flash.display.StageScaleMode 类的静态属性:EXACT_FIT, NO_BORDER,
NO_SCALE, 和 SHOW_ALL.
Flash 播放器默认的缩放模式是showAll。这种模式会按照影片原始比例进行缩放以适应播放器大
小。这样如果播放器的比例和影片的比例不一致就会导致电影边框的出现。设置应用程序的缩放模
式:
stage.scaleMode = StageScaleMode.SHOW_ALL;
注意到 stage 并不是个全局对象,但是它是任何可视化对象的一个属性,因此这个语句在sprite 类
或继承自 DisplayObject 类里都可以。
noBorder 模式在保持原始比例下进行缩放以适应播放器,但是,如果播放器和影片比例不匹配,影
片显示不下的会被剪切掉,使用下面的语句设置:
stage.scaleMode = StageScaleMode.NO_BORDER;
exactFit 模式缩放影片适应播放器,它改变了电影原始比例,如果必要,它会匹配播放器,这样电
影总是填充整个播放器,但是这样电影中的元素可能会扭曲,代码如下:
stage.scaleMode = StageScaleMode.EXACT_FIT;
noScale 模式即不进行缩放,保持原始比例。使用该模式不要忘了设置对齐方式(看 3.7 节):
stage.scaleMode = StageScaleMode.NO_SCALE;
scaleMode 属性值并不影响右键菜单里功能,不过你可以禁用菜单里的缩放功能,看3.8 节。
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 11 页 共 17 页
3.7. 改变对齐方式
问题
我要改变影片的对齐方式
解决办法
使用 stage.align 属性
讨论
默认下Flash 电影会居中显示。可以利用任何可视化对象的stage.align属性来重新设置电影的对齐
方式。flash.display.StageAlign 类的属性:
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 12 页 共 17 页
3.8. 隐藏Flash播放器的菜单项
问题
我要隐藏右键菜单
解决办法
不能够完全改变Flash 播放器的右键弹出菜单,但是可以设置stage.showDefaultContextMenu 属
性为false来最小化菜单项。
讨论
默认下Flash播放器右键弹出菜单的项目有:
Zoom In
Zoom Out
Show All
Quality (Low, Medium, or High)
Settings
Print
Show Redraw Regions (debug 版本)
Debugger (debug 版本)
About Adobe Flash Player 9
通过下面的语句可以移除许多项目,Settings和About 是不能移除的:
stage.showDefaultContextMenu = false;
遗憾的是,Flash 没有提供方法完全禁用右键菜单。
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 13 页 共 17 页
3.9. 检测设备音频
问题
我要确定播放器正在使用的音频设备.
解决办法
使用 flash.system.Capabilities 类的 hasAudio 和 hasMP3 属性
讨论
如果用户系统有播放音频的能力,则 flash.system.Capabilities.hasAudio 属性就返回True 。这实
际上很重要,如果目标设备不支持音频,那就要避免强制用户下载音频内容(因此音频内容都比较
大)。
// 只有当播放器可以播放声音才载入包含声音的.swf
if (flash.system.Capabilities.hasAudio) {
content = "sound.swf";
} else {
content = "silent.swf";
}
即时系统有播放音频能力也不意味着它有播放mp3 的能力。因此当发布含有mp3 内容时应用
flash.system.Capabilities.hasMP3 属性检测下目标设备。
if (flash.system.Capabilities.hasMP3) {
var url:URLRequest = new URLRequest("sound.mp3");
sound = new Sound(url);
sound.play( );
} else {
// code to load an external .swf containing a ADCP sound
}
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 14 页 共 17 页
3.10. 检测设备视频
问题
我要确定目标设备是否可以播放视频
解决办法
使用 flash.system.Capabilities 类的hasEmbeddedVideo, hasStreamingVideo, 和 hasVideoEncoder 属

讨论
检测用户端是否能播放视频也同样重要,使用flash.system.Capabilities.hasStreamingVideo 属性检测
是否能播放视频流。如果返回 false,就可以让用户下载内嵌视频的.swf 文件,在这之前也要用
flash.system.Capabilities.hasEbeddedVideo 确定,看下面的代码:
if(flash.system.Capabilities.hasStreamingVideo) {
// 播放视频流
}
else if(flash.system.Capabilities.hasEmbeddedVideo) {
// 下载内嵌视频的swf文件
}
else {
}
如果应用程序需要视频流编码,比如传送摄像机视频流,还要确定系统是否具有编码能力,使用
flash.system.Capabilities.hasVideoEncoder 属性检测。
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 15 页 共 17 页
3.11. 提示用户改变播放器设置
问题
我要打开用户的Flash 播放器设置对话框窗口
解决办法
使用 flash.system.Security.showSettings( ) 方法.
讨论
flash.system.Security.showSettings( ) 方法打开播放器设置对话框,它包含多个标签,也可以调用该方
法时传递参数给它直接打开相应标签,该参数字符串是 flash.system.SecurityPanel 类的静态属性:
SecurityPanel.CAMERA
摄像机面板
SecurityPanel.DEFAULT
默认面板
SecurityPanel.LOCAL_STORAGE
本地存储面板
SecurityPanel.MICROPHONE
话筒面板
SecurityPanel.PRIVACY
安全控制面板
SecurityPanel.SETTINGS_MANAGER
设置管理面板会打开浏览器进行更多设置
如果没有传递参数,默认使用 SecurityPanel.DEFAULT. 下面的例子打开本地存储面板:
flash.system.Security.showSettings(SecurityPanel.LOCAL_STORAGE);
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 16 页 共 17 页
3.12. 处理系统安全
问题
我要在应用程序中载入其他域的swf文件,并且允许它访问程序中的 ActionScript
解决办法
使用flash.system.Security.allowDomain( ), flash.system.Security.allowInsecureDomain( ),或 一个政策
文件。
讨论
很多情况下应用程序有多个分布在不同域里的swf 组成。如果你要载入外部域的swf 文件,需要通
过 flash.system.Security.allowDomain( ), flash.system.Security.allowInsecureDomain( ), 或一个政策文
件设定
假设accessing.swf 在mydomain.com,它要访问otherdomain.com 中的accessed.swf 中的一个变量,
而默认accessed.swf是不允许外部域的swf访问它,为了解决这个问题,在accessed.swf中加入以下
语句:
flash.system.Security.allowDomain("http://mydomain.com");
允许指定的域可以访问它。
也许你会注意到,被载入的swf 如果要访问载入它的swf 是不可以的,同样,载入它的swf 也要加
入上面的语句设置。
域名可以是字符串形式,也可以使IP地址。如果你想让所有域都能访问它,可以设置为 "*"。 However,
但这样做可能会导致安全问题,不推荐。
如果 accessed .swf 文件在基于https://的服务器里,默认它不能被基于http://的域访问,设置
flash.system.Security.allowDomain( )也没用,这时应该使用flash.system.Security.allowInsecureDomain( )
设置非安全的http 域可以访问。
这个办法虽好,但是如果经常变动域名就要重新编译swf 文件就麻烦了,最好的办法是创建一个策
略文件.
ActionScript 3 Cookbook 中文版
第三章. 运行时环境
第 17 页 共 17 页
该策略文件是一个 XML 文件,列出了被允许的域:
<?xml version="1.0"?>
<!-- http://www.mydomain.com/crossdomain.xml -->
<cross-domain-policy>
<allow-access-from domain="www.otherdomain.com" />
<allow-access-from domain="*.adobe.com" />
<allow-access-from domain="123.45.67.89" />
</cross-domain-policy>
该文件被命名为 crossdomain.xml。通过 flash.system.Security.loadPolicyFile( )读取文件,参数为指定
crossdomain.xml 文件的URL字符串。
指定任何域都可访问:
<allow-access-from domain="*" />
阻止任何域访问:
<cross-domain-policy>
</cross-domain-policy>

2007年8月9日 @ 08:20

ActionScript 3 Cookbook 中文版 第二章. 自定义类

ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 1 页 共 17 页
第二章. 自定义类
2.0. 简介
2.1. 创建自定义类
2.2. 类的保存
2.3. 创建成员属性
2.4. 创建静态方法或属性
2.5. 创建子类
2.6. 覆盖父类方法
2.7. 创建常量
2.8. 发送事件
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 2 页 共 17 页
2.0.简介
ActionScript 3.0 最本质的东西就是类,也就说它是面向对象的。 ActionScript 3.0 在面向对象基础
上重新构建了ActionScript 核心。如果在Flex上编写ActionScript 3.0,代码都被放在<mx:Script> 标
签内,所有ActionScript 都必须以类的形式出现。这一章讨论在ActionScript 3.0 上编写自定义类。
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 3 页 共 17 页
2.1. 创建自定义类
问题
我要编写自己的类
解决办法
保存一个以.as 扩展名的新文件,类名和文件名相同,编写如下结构:
package package {
public class Class {
}
}
讨论
在ActionScript 3 中,类是最基本的编程结构,所以必须先掌握编写类的基础知识。对于初学者,
所以得类都必须放在.as文件中,每个as文件里只能定义一个public 类,而且类名字要与文件名相
同。比如:你的类名为 Example ,那么文件名必须为 Example.as.
在 ActionScript 3.0 中所有的类都必须放在包中。包是对类进行分类的单位,其意义相当于文件系
统的目录。包路径相对于classpath(类路径),默认的类路径就是项目的根目录(就是包含mxml
文件的所在目录),因此顶级的包目录就是项目根目录。包申明如下:
package name {}
如果类定义在顶级包中,那么包名可以不指定,如:
package {}
当类文件保存在子目录,那么包名就是它的保存目录,例如,文件保存在example 目录,那么包这
样申明:
package example {}
如果类文件保存在 example 目录的子目录 subpackage, 应这样申明:
package example.subpackage {}
包是很重要的,它可以避免类名称空间冲突。例如,有两个开发者写了两个类文件都叫
MessageManager. 这两个类虽有相同名字,但是完成不同的任务,因此你不能把这两个类放在一
起,如果这样做,编译器将不知道调用哪个,一个办法是取个唯一的类名字。
你可以取名字叫 EmailManager 和 BinarySocket- MessageManager, 这是可以的,但是如果你管
理成千上万的类这时就很困难了。因此用包可以很好的解决这个问题,即使你有很多相同的类名,
只要它们不在同一个包就不会冲突,如把 MessageManager 放在net.messaging.email 包另一个
放在net.messaging.binarysocket 包中。
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 4 页 共 17 页
一般取包名都以自己的网站域名,这样可以最大限度避免和别人的包名相冲突。
当有多个项目公用一些类,那么这些类直接被放在主包 中的子目录中。例如,上面的
MessageManager 类放在com.examplecorp.net.messaging.email 和
com.examplecorp.net.messaging.binary- socket 包中。
下一步就是申明类自身:
public class Name {
}
类申明必须在包内。下面的代码在顶级包中定义了叫 Example 的类:
package {
public class Example {
}
}
类主体在括号内定义,包括属性,方法。属性就是和类关联的变量,使用var 关键字申明他们,属
性也有修饰符指定其范围。修饰符有:
private
该属性只有类实例自身可访问.
public
该属性可以被任何类实例访问(若直接被类访问可设置成static)
protected
该属性只被自身类实例或派生类实例访问。
Internal
该属性可被包内的类实例访问。
默认情况下是属性被指定为 internal ,除非自己指定修饰符。大多数情况,属性被指定为 private 或
protected。按照习惯约定,private 和 protected 申明的属性名称都在前面加上下划线。看下面的
例子:
package {
public class Example {
private var _id:String;
}
}
与类关联的还有方法,你可以使用function 关键字像申明函数那样申明方法。和属性一样,方法也
有修饰符(public, private, protected, internal)。如果方法被类实例访问可设置为public(直接被类
访问则加上static).如果方法只在类内方法则被设置为 private 或 protected。下面的代码申明一个
方法叫getId( ):
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 5 页 共 17 页
package {
public class Example {
private var _id:String;
public function getId( ):String {
return _id;
}
}
}
按照约定,方法名称的起始字符必须为小写。每个类都有个和自己类名相同的方法,该方法称为构
造函数,用它为创建新的实例时进行初始化工作。在 ActionScript 3.0 中,所有的构造函数都是
public ,不像标准的方法,构造函数不能有返回值,也不能申明有返回类型。下面的代码申明了构造
函数:
package {
public class Example {
private var _id:String;
public function Example( ) {
_id = "Example Class";
}
public function getId( ):String {
return _id;
}
}
}
下面展示如何构造一个新的 Example 类实例:
var example:Example = new Example( );
trace(example.getId( )); // 显示: Example Class
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 6 页 共 17 页
2.2. 类的保存
问题
把类文件保存到哪里呢
解决办法
保存与包名称相符的目录中。
讨论
类文件保存在与包路径相符的目录中,比如:
com.examplecorp.net.messaging.email.MessageManager
必须保存在 com/examplecorp/net/messaging/email/ 目录下.
编译器就知道去哪里找类。还有编译器也必须知道根目录是什么。例如,编译器需要知道 com 目
录在哪里,编译器是通过classpath来找到com 目录。默认的classpath就是Flex或Flash项目的
根目录。例如,如果com 目录和.fla 文件或mxml 文件的同一目录,编译器就能找到这些类。其实
你也可以保存到其他目录,例如,如果你有个公共库被多个项目使用,难道要拷贝多份到每个项目
中,其实你可以编辑项目中的classpath来加入该库,这样不需要拷贝就能找到你的自定义类了。
右键点击工程名,选择Properties,选择Build Path,在Source Path 中添加和修改classpath 就可
以了。如果你只使用SDK,那么当编译项目时必须设置classpath。使用mxmlc (Flex SDK中包含
的命令行编译器), 加上 -source-path 选项, 跟上类目录,例如:
mxmlc -source-path . C:\libraries ExampleApplication.as
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 7 页 共 17 页
2.3. 创建成员属性
问题
我要创建public 成员属性
解决办法
使用隐含 getters 和 setters.
讨论
正如2.1节中所说的那样属性应该被申明为 private 或 protected。 public 属性并不是什么好主意,
因为他不能体现封装性。要尽量做好封装,这意味着类不能暴露他的内部细节,public 属性使开发
者能轻易破坏类或类实例。下面的简单例子是用了Public 属性:
package {
public class Counter {
public var count:uint;
public function Counter( ) {
count = 0;
}
}
}
构造一个Counter 实例, 然后改变count 属性值,如:
var counter:Counter = new Counter( );
counter.count++;
但是,如果count属性被规定不能超过100,那么外部修改很可能无法保证,这样破坏了这个规定,
一个办法就是设置 getters 和 setters,如下:
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 8 页 共 17 页
package {
public class Counter {
private var _count:uint;
public function Counter( ) {
_count = 0;
}
public function getCount( ):uint {
return _count;
}
public function setCount(value:uint):void {
if(value < 100) {
_count = value;
}
else {
throw Error( );
}
}
}
}
另一个办法就是用隐式getters 和 setters. 隐式 getters 和 setters 就像申明方法那样,但是看起
来又像属性getter 语法如下:
public function get name( ):Datatype {
}
setter 语法:
public function set name(value:Datatype):void {
}
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 9 页 共 17 页
下面定义隐式 getter 和 setter 方法:
package {
public class Counter {
private var _count:uint;
public function Counter( ) {
_count = 0;
}
public function get count( ):uint {
return _count;
}
public function set count(value:uint):void {
if(value < 100) {
_count = value;
}
else {
throw Error( );
}
}
}
}
counter.count = 5;
trace(counter.count);
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 10 页 共 17 页
2.4. 创建静态方法或属性
问题
我要创建的方法和属性不需要类实例就能直接访问。
解决办法
使用static 修饰符申明属性或方法
讨论
默认下属性和方法是属于实例的,例如 Example 类定义了 _id 属性和 getId( ) 方法,那么每个
Example 实例都有自己的_id 属性和getId( ) 方法。但是有种情况你希望属性或方法是和类相关联
而不是类实例,也就说不管有多少个类实例,都只有一个公共属性或方法,这样的属性和方法称为
静态属性和方法。
Flash 播放器的类中就有些这样的例子,比如 Math 类中定义了 round( ) 方法,round( ) 方法就是
个静态方法,因此可以通过类直接访问:
trace(Math.round(1.2345));
Math 类包含全部是静态方法,但是类也可以同时含有静态方法和实例方法及属性。比如 String 类
有多数实例属性和方法,然而fromCharCode( ) 方法是静态的,该方法返回字符码。
下面的代码申明了一个静态的私有的属性_example:
static private var _example:String;
修饰符的顺序没有关系,比如static private 和 private static 是一样的.
static 最重要的用处就是在单态模式下,即类只能创建一个实例,单态类有一个private static 属性
用来存储类实例,然后在一个 public static 方法中访问这个实例。
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 11 页 共 17 页
2.5. 创建子类
问题
我要创建派生类
解决办法
使用extends关键字继承已有的类
讨论
如果新建的类和已有的类拥有公共特性但是又比已有类有更多细节,这时去重写所有的代码还不如
从已有类中继承公共特性再添加专有代码。这时这个新类就是已有类的一个子类。
使用extends关键继承超类:
public class Subclass extends Superclass
子类可以引用任何超类中的 public 或 protected 的属性和方法,private 属性和方法是不能够访问
的。
继承性是非常强大的功能,但是另一方面如何正确的使用继承也很重要。在写子类之前你要确定新
类和超类是否已经有子类关系,这里有两种基本关系类型:继承和组合。你经常要确定类之间是"is a"
关系还是"has a" 关系:
"Is a" 关系是继承关系。如一个应用程序管理着一个图书馆的藏书。
"Has a" 关系是组合关系。大多数类使用组合,而且比继承更有伸缩性(然而需要更多代码)。例如
一本书不是一个作者,但是它有一个作者。
图书馆有不同类型的藏品包括书和DVDs。很明显书和DVDs 有不同的类型数据。书包括页数和作
者,而DVDs 则有播放时间数,演员,导演等等,但是也有一些公共数据,比如所有图书馆都有用
一些唯一的数字编号或命名规则来管理这些藏品. 而且每个种类都有标题或名称,这时你可以定义
个类来归纳这些公共信息:
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 12 页 共 17 页
package org.examplelibrary.collection {
public class LibraryItem {
protected var _ddc:String;
protected var _id:String;
protected var _name:String;
public function LibraryItem( ) {}
public function setDdc(value:String):void {
_ddc = value;
}
public function getDdc( ):String {
return _ddc;
}
public function setId(value:String):void {
_id = value;
}
public function getId( ):String {
return _id;
}
public function setName(value:String):void {
_name = value;
}
public function getName( ):String {
return _name;
}
}
}
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 13 页 共 17 页
书和DVDs 都是LibraryItem 的一个种类. 接下来很自然就是定义Book 类和 DVD 类,继承自
LibraryItem,Book 类类似于:
package org.examplelibrary.collection {
import org.examplelibrary.collection.LibraryItem;
public class Book extends LibraryItem {
private var _authors:Array;
private var _pageCount:uint;
public function Book( ) {}
public function setAuthors(value:Array):void {
_authors = value;
}
public function getAuthors( ):Array {
return _authors;
}
public function setPageCount(value:uint):void {
_pageCount = value;
}
public function getPageCount( ):uint {
return _pageCount;
}
}
}
默认下可以继承任何类,但是如果你不要这个类再被继承,可以添加final 修饰符申明该类:
final public class Example
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 14 页 共 17 页
2.6. 覆盖父类方法
问题
我要对从父类继承过来的方法进行重新实现。
解决办法
父类的方法必须申明为public 或 protected。当申明子类的实现时使用 override 修饰符
讨论
通常子类继承父类的所有方法而不做任何修改,但有些情况,继承过来的方法需要重新申明,实现
与父类的方法不同。这时就要覆盖方法,该方法必须加上override 修饰符。如下面的例子,首先定
义一个父类Superclass:
package {
public class Superclass {
public function Superclass( ) {}
public function toString( ):String {
return "Superclass.toString( )";
}
}
}
下一步,定义Subclass 继承自Superclass:
package {
public class Subclass extends Superclass {
public function Subclass( ) {}
}
}
默认情况下,Subclass 继承 Superclass 实现的toString( ) 方法:
var example:Subclass = new Subclass( );
trace(example.toString( )); // 显示: Superclass.toString( )
如果你要 toString( ) 方法返回不同的值,就要覆盖它,如下:
package {
public class Subclass extends Superclass {
public function Subclass( ) {}
override public function toString( ):String {
return "Subclass.toString( )";
}
}
}
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 15 页 共 17 页
覆盖方法,则该方法必须与父类的方法完全相同,包括参数数量和类型及返回类型,如果不一致,
编译器就会报错。
有时你要覆盖方法是为了实现完全不同的功能,但有时你只是要增加一些东西,这时你可以调用父
类方法:
super.methodName( );
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 16 页 共 17 页
2.7. 创建常量
问题
我要怎么申明常量
解决办法
和申明属性差不多,只是在前面多了const 关键字
讨论
常量的值一旦定义就不可改变,这在有时候是很有用的。比如你有个复合的值需要经常用到,这时
就可以把它当作简单的标示直接引用。Math.PI 就是个常量,MouseEvent.MOUSE_UP也是常量,
包含mouseUp值,设定这些常量可以减少出错,比如下面的代码错误你难以觉察出来:
// 下面的代码没错,但是mouseUp 被写成了 mousUp,因此该代码无效。
addEventListener("mousUp", onMouseUp);
但是使用常量,编译器就会给出错误提示:
// 导致编译器错误
addEventListener(MouseEvent.MOUS_UP, onMouseUp);
常量也可以有static 和public 修饰符,这时常量一申明就要赋值:
static public const EXAMPLE:String = "example";
按照约定,常量都要大写,这样可以和其他变量或属性区别开来。
ActionScript 3 Cookbook 中文版
第二章. 自定义类
第 17 页 共 17 页
2.8. 发送事件
问题
我要发送事件
解决办法
继承 flash.events.EventDispatcher 然后调用 dispatchEvent( ) 方法
讨论
事件在对象之间的通讯起到至关重要的作用,有了它才能开发出功能强大的系统。Flash Player 9, 的
flash.events.EventDispatcher类有一套事件发送机制。所有的事件都继承自EventDispatcher (比如
NetStream and Sprite). 如果你要定义个类要发送事件也要继承EventDispatcher,如:
package {
import flash.events.EventDispatcher;
public class Example extends EventDispatcher {
}
}
EventDispatcher 类有个公共方法addEventListener( ) 和 removeEventListener( ), 通过它的子
类来注册事件监听。 EventDispatcher 还有个 protected 方法 dispatchEvent( ) 来发送事件。
dispatchEvent( ) 方法至少需要flash.events.Event 对象或Event 的子类作为参数。

2007年8月9日 @ 08:19

ActionScript 3 Cookbook 中文版 第一章. ActionScript 语言基础

ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 1 页 共 34 页
第一章. ActionScript 语言基础
1.0. ActionScript 3.0 Cookbook 概述
1.1. 新建一个 ActionScript 工程
1.2. 自定义应用程序属性
1.3. 在哪里写ActionScript 代码呢
1.4. 如何跟踪信息
1.5. 处理事件
1.6. 响应鼠标和键盘事件
1.7. 算术运算
1.8. 逻辑运算
1.9. 执行条件语句
1.10. 执行复杂的条件语句
1.11. 某段时间重复执行一种操作
1.12. 长时间执行一个任务
1.13. 创建可重用代码
1.14. 增强代码可重用能力
1.15. 从方法中退出
1.16. 获得方法的执行结果
1.17. 处理错误
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 2 页 共 34 页
概述
在Ajax 和 微软 WPF 袭来之前,Macromedia 率先推出基于Flash 的RIA解决方案,用于创建具
有桌面程序富有交互和多功能的Web应用程序,我们称之为“Rich Internet Application”。现在,新
东家 Adobe 更是赋予了Flash超越Web之能力,使之成为完整的开发环境。
除了理论,本书来源于实际ActionScript 应用,超过300 个解决方法用于解决各种编写代码中遇到
的问题。比如:
Ÿ 检测用户Flash 播放器版本或操作系统
Ÿ 开发自定义类
Ÿ 数据和类型格式化
Ÿ 字符串的使用
Ÿ 开发用户界面组件
Ÿ 声音和视频的使用
Ÿ 使用Flash Remoting and web services 实现远程过程调用
Ÿ 读取,发送和搜索XML数据
Ÿ 更多。。。。。。
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 3 页 共 34 页
1.1. 新建一个 ActionScript 工程
问题
运行 Flex Builder 2 然后新建一个ActionScript 工程
解决方法
使用 新建 ActionScript 工程向导来建立你的工程
讨论
一个ActionScript 工程一般至少包含一个class 文件和一个用来放置编译输出的SWF 和HTML 的
bin目录。还包含一些设定来告诉编译器怎么去编译工程。我们只要用向导创建项目,其他的事都交
给Flex Builder 2 维护就行了。有几种方法启动向导,你可以使用菜单中的File ->New->ActionScript
Project, 或者点击左上方的New 按钮,然后从列表中选择 ActionScript Project 。
打开先导后选择 New ActionScript Project ,下一步输入工程名称,比如 ExampleApplication, 当
你创建好工程后,我们会看到主应用程序文件被设置成工程名加上 .as 扩展名。
点击下一步,这里可以添加自定义类,额外的库,或者指定输出目录名称来代替默认的bin 目录,
不过现在我们不必关心这些,点击Finish完成向导。
接着Flex Builder 2 为我们做好了一切。在Navigator 视图上我们看到 ExampleApplication 工程,
包含了一个空的bin 目录和一个ExampleApplication.as 类文件。注意创建的主类文件已经在编辑
视图中打开了,而且在Outline 视图我们看到一个类树型结构,它包含了类方法,属性和import 语
句。
运行我们的程序,只要点击上面的绿色的三角形图标按钮,右边的小虫图标的按钮是调试按钮,两
个命令都是生成.swf 和 html 文件,它会启动浏览器自动运行我们的程序。
到现在我们还没有添加任何语句,这相当于在Flash IDE 中一个空白的 .fla 文件一样, 当运行的时
候除了蓝色的背景什么也没有。
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 4 页 共 34 页
1.2. 自定义应用程序属性
问题
我要改变SWF 的尺寸或背景颜色
解决方法
指定项目属性里的编译器参数或者class文件的 metadata
讨论
不像早期版本的Flash,ActionScript 3.0 编译器真正是一个命令行编译器。你可以通过命令行再加
上一长串参数来创建类或目录,在eclipse 里让这一切变得更简单些。
当建立ActionScript 工程后,默认情况下会生成500x375 尺寸的 .swf, 帧速为24/秒,背景色为蓝
色。我们可以改变这些设定,有几种方法。
第一种方法就是通过ActionScript 编译器参数改变编译器设定。右键点击工程,在菜单中选择
Properties ,然后在左边选择ActionScript Compiler,在右边找到"Additional compiler arguments."
在这里就可以输入参数了,下面是些常见的参数
-default-size width height
-default-background-color color
-default-frame-rate fps
可以这样写:
-default-size 800 600
-default-background-color 0xffffff
-default-frame-rate 31
第一个参数设定输出swf 尺寸为800x600 象素. 第二个参数设定背景色为白色,第三个参数设定播
放帧速为31帧每秒。多个参数可以这样写:
-default-size 800 600 -default-frame-rate 31
第二种方法就是通过类文件种的metadata 来改变设定。Metadata 中包含的语句不会立即被解释,
但是在编译的时候编译会去检测。下面的语句具有等同效果
[SWF(width="800", height="600", backgroundColor="#ffffff", frameRate="31")]
这一行语句放在import 之后,类定义之前,如:
package {
import flash.display.Sprite;
[SWF(width="800", height="600", backgroundColor="#ffffff", frameRate="31")]
public class ExampleApplication extends Sprite
{
public function ExampleApplication()
{
}
}
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 5 页 共 34 页
1.3. 在哪里写ActionScript 代码呢
问题
当你有了ActionScript 工程后,接着就需要知道任何输入代码。
解决方法
在类结构中或方法体中添加 ActionScript 代码
讨论
在以前的ActionScript 1.0 和 2.0 中, 有多种途径添加代码:在时间线上,按钮上或电影剪辑上,在
电影剪辑的时间线上通过#include命令引入外部的as文件或class文件。但是 ActionScript 3.0 是
完全基于类的,所以所有的代码都必须放置在类文件中。
当你创建一个新的 ActionScript 工程后,主类文件被自动创建,并且在代码视图中代开了,刚开始
的代码大概是这样的:
package {
import flash.display.Sprite;
public class ExampleApplication extends Sprite
{
public function ExampleApplication( )
{
}
}
}
可能你很熟悉 ActionScript 2.0中的类, 但是3.0 发生了很多变化,这些我们将在第二章讨论,在这
里先学完基础概念先。
首先注意到代码顶层有个关键字 package ,Packages(包) 是用来组织一群相关联的类文件的。
在 ActionScript 2.0, 包是用来判断类文件的路径。在 ActionScript 3.0 中必须指定包,例如,我们
有个utility类包,要这样申明:
package com.as3cb.utils {}
如果你不指明包名,那么该类就输入最顶层的默认包。
接下来,加入 import 语句,引入一个类就相当于在当前的代码文件中创建了使用该类的快捷方式,
这样我们就不需要输入全路径来使用它了。例如,你可以使用下面的 import 语句:
import com.as3cb.utils.StringUtils;
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 6 页 共 34 页
这样我们就可以直接引用 StringUtils 这个类了。从flash.display 引入Sprite 类是因为默认的类文
件继承了Sprite 类。
接下来就看到我们的主类 ExampleApplication,注意到在class 关键字前有个关键字public ,表明
该类是共有的。最后有个公共方法,方法名和主类一样,这种方法称为构造器,当一个类实例被创
建时,其构造器会被自动执行,在这里,当swf 文件被Flash 播放器载入时构造器就会被执行。
In this case, it is executed as soon as the .swf is loaded into the Flash player. So where do you put
your code to get it to execute? Generally, you start out by putting some code in the constructor
method. Here's a very simple example that just draws a bunch of random lines to the screen:
package {
import flash.display.Sprite;
public class ExampleApplication extends Sprite {
public function ExampleApplication( ) {
graphics.lineStyle(1, 0, 1);
for(var i:int=0;i<100;i++) {
graphics.lineTo(Math.random( ) * 400, Math.random( ) * 400);
}
}
}
}
保存然后运行程序,浏览器会打开一个html 文件,显示一个swf 里画了100条随即直线。正如你所
看到的,当swf 被播放器载入后构造器就会被执行。
在这里联系中,我们把代码直接写在了构造器中,但时最好的办法是在构造器中引用一个方法,在
这个方法中添加代码.
对于新手来说,现在你已经学会了如何添加代码了。
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 7 页 共 34 页
1.4. 如何跟踪信息
问题
你需要在运行时跟踪信息或某个数据变量
解决办法
使用 trace 函数,把数据传给它,运行程序,你会发现信息已经在Eclipse的控制台下输出了。
讨论
你可以跟踪一个消息或一个变量的值,也可以输出任何其他数据,就像你在早期的版本中那样,比
如:
trace("Hello, world");
trace(userName);
trace("My name is " + userName + ".");
一旦swf在外部浏览器里运行,就没办法捕获trace输出的信息了,幸运的是Flex Builder2有Console
视图,Console视图就相当于Flash 的Ouput面板。
需要注意的是使用trace 则必须在调试模式下运行程序,这样才能在Console 视图显示数据,下面
的代码创建一个变量,然后赋值,然后用trace输出。
package {
import flash.display.Sprite;
public class ExampleApplication extends Sprite {
public function ExampleApplication( ) {
var userName:String = "Bill Smith";
trace("My name is " + userName + ".");
}
}
}
现在在调试模式下运行程序,运行完关闭浏览器,你会看到在Eclipse下已经输出数据了。
要运行debug 版本的程序,必须要安装debug 版本的Flash 播放器。否则会显示错误信息,另外
debug版本的播放器可以把输出信息到一个文件上,查找mm.cfg文件。一般信息如下:
mm.cfg 文件允许你设置如下变量:
TraceOutputFileEnable 设置值为 0 (不写入文件) 或 1 (写入文件).
TraceOutputFileName 文件路径,如果没有指定,会在mm.cfg 的同目录下生成一个叫flashlog.txt
文件
ErrorReportingEnable 设置值为 0 (不输出错误信息到文件) 或 1 (输出错误信息). 默认为0
MaxWarnings 写入文件的错误信息数量。如果为0 则没有限制。
例子:
TraceOutputFileEnable=1
TraceOutputFileName=C:\flex.log
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 8 页 共 34 页
1.5. 处理事件
问题
我要重复执行某段代码
解决办法
在 enterFrame 事件中添加监听器和关联处理方法
讨论
在ActionScript 2.0 中处理enterFrame 事件是很简单的,你只要创建时间线函数调用
onEnterFrame 然后每次新帧开始时就会自动调用。在 ActionScript 3.0 中有各种各样的事件需要
控制,访问他们也是不难的。
如果你熟悉ActionScript 2.0中的EventDispatcher 类的话,你就很好理解 ActionScript 3.0 事件句
柄了。要广播 enterFrame 事件,你要告诉你的程序去监听这个事件然后指定回调函数。用
addEventListener 方法可以做到:
addEventListener(type:String, listener:Function)
type 参数指出你要监听的事件类型,比如"enterFrame". 然而自己输入这些字符串容易出错,最好
的办法就是调用 Event 类的静态成员属性:导入Event 类,调用addEventListener 方法:
addEventListener(Event.ENTER_FRAME, onEnterFrame);
第二个参数onEnterFrame,指向类中定义的回调函数,该函数需要传递进EVENT 的一个实例:
import flash.events.Event;
private function onEnterFrame(event:Event) {}
event 对象包含一些于该事件有关的信息。这里有个简单的例子:画出一些随机线。
package {
import flash.display.Sprite;
import flash.events.Event;
public class ExampleApplication extends Sprite {
public function ExampleApplication( ) {
graphics.lineStyle(1, 0, 1);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void {
graphics.lineTo(Math.random( ) * 400, Math.random( ) * 400);
}
}
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 9 页 共 34 页
1.6. 响应鼠标和键盘事件
问题
我要处理鼠标或键盘事件
解决办法
监听和捕获处理鼠标和键盘事件
讨论
处理鼠标和键盘事件很类似于enterFrame 事件,这些在1.5 节已经讨论过,只是略有不同。对于
鼠标事件,主程序不会直接接收,需要通过一个可视组件监听它(关于可视组件会在第5章讨论)。
下面的例子创建一个sprite,添加到可视组件列,然后在它上面画了个矩形:
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
public class ExampleApplication extends Sprite {
private var _sprite:Sprite;
public function ExampleApplication( ) {
_sprite = new Sprite( );
addChild(_sprite);
_sprite.graphics.beginFill(0xffffff);
_sprite.graphics.drawRect(0, 0, 400, 400);
_sprite.graphics.endFill( );
注意:鼠标事件名称被定义在 MouseEvent 类中,事件处理函数需要传递进一个MouseEvent 类
实例,现在为sprite加入鼠标监听器:
_sprite.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
_sprite.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
接着,定义两个处理函数onMouseDown 和 onMouseUp:
private function onMouseDown(event:MouseEvent):void {
_sprite.graphics.lineStyle(1, 0, 1);
_sprite.graphics.moveTo(mouseX, mouseY);
_sprite.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
private function onMouseUp(event:MouseEvent):void
{
_sprite.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 10 页 共 34 页
onMouseDown 方法设置画线的类型,移动画刷到鼠标点击位置,然后添加了第三个鼠标监听器监
听 MouseMove 事件
onMouseUp 方法用removeEventListener 方法移除监听器,它和addEventListener 方法具有相同
语法结构,只是作用相反罢了
最后,定义onMouseMove 函数
private function onMouseMove(event:MouseEvent):void {
_sprite.graphics.lineTo(mouseX, mouseY);
}
}
}
这样就建立了一个事件驱动的绘画程序。
键盘事件的处理简单一些,只需要监听和响应键盘事件,接受这些事件的对象必须出于激活状态。
我们需要在主程序中加入这一行:
stage.focus = this;
下面的例子展示一个简单的类,它监听键盘的 keyDown 事件,输出按键的字符码,
package {
import flash.display.Sprite;
import flash.events.KeyboardEvent;
public class ExampleApplication extends Sprite {
public function ExampleApplication( ) {
stage.focus = this;
addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
}
private function onKeyDown(event:KeyboardEvent):void {
trace("key down: " + event.charCode);
}
}
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 11 页 共 34 页
1.7. 算术运算
问题
我要修改一些东西,比如sprite 的角度和位置
解决办法
使用复合赋值运算来改变变量或属性的值
讨论
经常我们需要的新值需要建立在旧值的基础上,比如说,我要移动sprite 到离当前位置向右10个像
素的地方。
一条赋值语句通过赋值操作符(=号)建立,=号右边表达式被运算出来然后其结果存储在左边的变
量或属性中。
// 给变量 quantity 增加6
quantity = quantity + 6;
在这些算术操作中,还有些很便利的复合操作符,如 +=, -=, *=, and /= 会被经常用到。
下面两个语句都是给quantity 加上6:
quantity = quantity + 6;
quantity += 6;
下面两个语句都是给quantity 减去6:
quantity = quantity - 6;
quantity -= 6;
下面两个语句让quantity 乘以 factor:
quantity = quantity * factor;
quantity *= factor;
下面两个语句让 quantity 除以 factor:
quantity = quantity / factor;
quantity /= factor;
如果只是增加1或减少1,还可以象下面这样写
这个语句让quantity 增加1:
quantity++;
下面的两个语句效果相同
quantity += 1;
这个语句让 quantity 减去1:
quantity --;
下面的两个语句效果相同:
quantity = quantity 1;
quantity -= 1;
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 12 页 共 34 页
自增和自减运算符还有前缀写法:
var quantity:Number = 5;
trace(quantity++); // Displays: 5
trace(quantity); // Displays: 6
var quantity:Number = 5;
trace(++quantity); // Displays: 6
trace(quantity); // Displays: 6
回到起初的问题,你可以用这些操作符修改属性值。下面的代码指定了sprite每帧角度加5:
private function onEnterFrame(event:Event) {
_sprite.rotation += 5;
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 13 页 共 34 页
1.8. 逻辑运算
问题
我想检测两个值的大小
解决办法
使用==号来比较两个值,使用 isNaN( ) 来检测是否是有效值.
讨论
==号表达式总是返回布尔值来表示两个值是否相等。当两个数类型不同时,比较时会自动转换为相
同的类型再进行比较,如字符型的6和数字型的6比较的话被认为相等。
trace(5 == 6); // : false
trace(6 == 6); // : true
trace(6 == "6"); // : true
trace(5 == "6"); // : false
默认的工程项目,在运行上面的代码会出错。因为编译器被设置为强类型编译检测。关掉强类型检
测,会把数字型转换为字符型,然后再进行比较。一般不推荐关闭强类型检测,这样可能会引发一些
隐蔽的错误不利于程序稳定。
当两个数值不相等时,!=操作符将返回true,否则为false
trace(5 != 6); // : true
trace(6 != 6); // : false
trace(6 != "6"); // : false
trace(5 != "6"); // : true
同样,只有在关闭强类型检测后才能编译通过。
平时要注意不要把==写成=,否则会出现无法预料的错误。比如:
var quantity:int = 5;
// 下面的代码是错误的,正确应为 if (quantity == 6)
if (quantity = 6) {
trace("Rabbits are bunnies.");
}
trace("quantity is " + quantity); // 输出: quantity is 6
可以使用 is 操作符来检测数据类型
var quantity:int = 5;
if (quantity is int) {
trace("Yippee. It's an integer.");
}
然而有些数值是非法的。下面的代码中quantity 等于 NaN (一个表示无效数字的常数)
var quantity:Number = 15 - "rabbits";
NaN 虽然是无效的数值,但它的数据类型仍属于 Number ,
trace(typeof quantity); // 显示: "number"
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 14 页 共 34 页
所以,为了测试有个number 变量类型不是数字,但又是合法的number,尝试下这么写:
var quantity:Number = 15 - "rabbits";
if (quantity is Number) {
//看起来好像正确,实际上是错误的,因为quantity != NaN 结果被认为都是false
if (quantity != NaN) {
trace("Yippee. It's a number.");
}
}
为了检测一个数字是不合法的,要使用指定的函数isNaN( ) 看下面的例子:
var quantity:Number = 15 - "rabbits";
if (isNaN(quantity)) {
trace("Sorry, that is not a valid number.");
}
如果要检测相反条件,只要取反就可以,比如为了检测一个变量是个合法的number,使用!isNAN( ),
如下:
var quantity:Number = 15 - "rabbits";
if (!isNaN(quantity)) {
trace ("That is a valid number.");
}
当然了你还可以使用<和>比较符号来比较两个值得大小。
trace(5 < 6); // 显示: true
trace(5 > 5); // 显示: false
还有<= 和>= 符号
trace(5 <= 6); // 显示: true
trace(5 >= 5); // 显示: true
ActionScript 数据类型的比较有两个情况。在ActionScript 中,数据类型分为两类:基本类型
(string, number, and Boolean) 和复合类型(object, sprite, and array)。当比较基本类型时,是比较
他们的值,下面的例子中 quantity 和 total 被认为是相等的因为他们包含相同的值6
var quantity:Number = 6;
var total:Number = 6;
trace (quantity == total); // 显示: true
然而,当比较符合数据类型时是通过他们的“引用”来比较。当两个引用所指向的对象完全相同才被认
为是相等的,而不仅仅是对象的内容相同。例如,两个数组包含相同的内容,但是他们却不相等:
// 用相同的内容创建两个数组
var arrayOne:Array = new Array("a", "b", "c");
var arrayTwo:Array = new Array("a", "b", "c");
trace(arrayOne == arrayTwo); // 显示: false
只要当引用指向同一个object, array, 或 sprite 才相等. 例子:
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 15 页 共 34 页
// 创建一个简单的数组
var arrayOne:Array = new Array("a", "b", "c");
// 创建另一个变量指向同一个数组
var arrayTwo:Array = arrayOne;
trace(arrayOne == arrayTwo); // 显示: true
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 16 页 共 34 页
1.9. 执行条件语句
问题
我要当满足某些条件时才执行一些命令
解决办法
使用 if 或 switch 语句
讨论
我们经常需要让代码去有选择性的执行,这时可以使用 ActionScript 中的条件语句 if, switch, 或
三元条件运算符 (? :).
条件语句允许我们做出逻辑判断,某种情况下应该做什么。if 语句是最简单的判断语句,当我们遇
到多个可能的情况要处理,这时用switch更好些。而三元条件运算符是把检测和赋值都放在一行中
搞定,简化操作。
首先我们来看一下if 语句, if 语句以if 关键字开头,接着跟一对括号,括号内为测试表达式,后
面的大括号放入测试表达式成立时要执行的代码。
下面的代码检测 animalName 是否等于"turtle."
if (animalName == "turtle") {
// 如果相等 trace( ) 语句将被执行
trace("Yay! 'Turtle' is the correct answer.");
}
另外还可以加上 else 子句来处理当测试表达式不满足时的情况,要注意的是要看到trace()输出的
信息则必须让程序在debug模式下运行。我们把输出信息放到showMessage( ) 方法里,这样这个
函数就可以被重用了
if (animalName == "turtle") {
// 条件为真则执行
showMessage("Yay! 'Turtle' is the correct answer.");
}
else {
// 条件为假
showMessage("Sorry, you got the question wrong.");
}
还可以加入else if 子句,如果 if 条件为真则跳过 else if 子句,如果为假则继续判断 else if 字句
是否为真
if (animalName == "turtle") {
// 条件为真则执行
showMessage ("Yay! 'Turtle' is the correct answer.");
}
else if (animalName == "dove") {
//animalName == "dove"成立则执行
showMessage ("Sorry, a dove is a bird, not a reptile.");
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 17 页 共 34 页
还可以包含更多的 else if 子句,然而这种情况,最好的办法就是采用 switch 语句代替,因为switch
与 if 语句结构更加清晰和简洁。 但在某些特殊场合,用 if 可以达到优化性能的目的。
switch 语句包含三部分:
switch 关键字
每个switch 语句都以switch 关键字开始
测试表达式
测试表达式被括号包围,它的结果将决定执行哪段代码。
switch 语句主体
主体中一般包含多个cases子句或一个default 子句
Case 表达式
case 表达式将和 switch 表达式进行比较,如果相等就执行当前case 的主代码。.
Case 主体y
当所有的case表达式都不等于switch表达式,将执行default 主体。
switch (testExpression) {
case caseExpression:
// case body
case caseExpression:
// case body
default:
// case body
}
例子:
var animalName:String = "dove";
switch (animalName) {
case "turtle":
trace("Yay! 'Turtle' is the correct answer.");
case "dove":
trace("Sorry, a dove is a bird, not a reptile.");
default:
trace("Sorry, try again.");
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 18 页 共 34 页
一般情况下,在每个case主体最后都会加上 break 语句,这样执行完就会直接退出switch语句。
var animalName:String = "dove";
// 现在第2个case 主体将被执行
switch (animalName) {
case "turtle":
trace("Yay! 'Turtle' is the correct answer.");
break;
case "dove":
trace("Sorry, a dove is a bird, not a reptile.");
break;
default:
trace("Sorry, try again.");
}
当有多个匹配但是执行代码是一样的,这时可以这么写:
switch (animalName) {
case "turtle":
case "alligator":
case "iguana":
trace("Yay! You named a reptile.");
break;
case "dove":
case "pigeon":
case "cardinal":
trace("Sorry, you specified a bird, not a reptile.");
break;
default:
trace("Sorry, try again.");
}
ActionScript 还支持三元条件运算符 (? :), 它把条件测试和赋值语句都放在一行完成。总共有3 个
操作数,第一个是条件表达式,如果为真,则取第二个操作数为结果,否则去第三个操作数为结果。
varName = (conditional expression) ? valueIfTrue : valueIfFalse;
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 19 页 共 34 页
1.10. 执行复杂的条件语句
问题
我要在多个条件中做出决定
解决办法
可以使用逻辑运算符AND (&&), or (||), 和 NOT (!) 来创建符合条件语句。
讨论
ActionScript中的很多语句都能包含条件表达式。包括 if, while, 和 for 语句,如果测试两个条件都成
立可以使用逻辑运算符 AND , &&, (更多细节请看第14 章):
// 测试今天是否是3月17 号
var current:Date = new Date( );
if (current.getDate( ) == 17 && current.getMonth( ) == 3) {
trace ("Happy Birthday, Bruce!");
}
加入些括号让结构更加清晰:
// Check if today is April 17th.
if ((current.getDate( ) == 17) && (current.getMonth( ) == 3)) {
trace ("Happy Birthday, Bruce!");
}
这里使用了逻辑运算符OR , ||, 来测试是否其中有个条件成立:
// 测试是否是周末
if ((current.getDay( ) == 0) || (current.getDay( ) == 6) ) {
trace ("Why are you working on a weekend?");
}
还可以使用 NOT, !, 来测试条件不是真的:
// 检测名字不是Bruce.
if (!(userName == "Bruce")) {
trace ("This application knows only Bruce's birthday.");
}
上面的例子还可以这么写:
if (userName != "Bruce") {
trace ("This application knows only Bruce's birthday.");
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 20 页 共 34 页
任何布尔值或能得出布尔结果的表达式都能作为测试表达式:
// 检测如果sprite 是可见的,则输出信息
if (_sprite.visible) {
trace("The sprite is visible.");
}
NOT 运算符经常被用来检测是否是false:
// 检测如果 sprite 是不可见的,则输出信息:
if (!_sprite.visible) {
trace("The sprite is invisible. Set it to visible before trying this action.");
}
NOT 经常和OR 一起用:
// 检测既不是Bruce 有不是 Joey.
if (!((userName == "Bruce") || (userName == "Joey"))) {
trace ("Sorry, but only Bruce and Joey have access to this application.");
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 21 页 共 34 页
1.11. 某段时间重复执行一种操作
问题
我要在单帧里多次执行某个任务
解决办法
在单帧里使用循环语句多次执行某个任务,例如,使用 for 语句:
for (var i:int = 0; i < 10; i++) {
// 显示i.的值
TRace(i);
}
讨论
使用循环语句可以让你的代码更加简洁。容易阅读和维护。既可以用 while 也可以用 for 语句,但
是一般for 语句比较好用。两个循环语句都能达到相同结果,只是 for 语句对于大多数程序员来说
更熟悉些。
原形:
for (initialization; test; update) {
statement body
}
下面的例子输出0到999 的数字:
for (var i:int = 0; i < 1000; i++) {
trace(i);
}
trace ("That's the end.");
多个初始值或步进值可以用逗号分开,初始化多个变量var 关键字只需要使用一次,下面的例子展
示了每次i增加1,j 减小1,然后输出i和j:
for (var i:int = 0, j:int = 10; i < 10; i++, j--) {
trace("i is " + i);
trace("j is " + j);
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 22 页 共 34 页
for 语句还可以嵌套,看下面的例子:
for (var i:int = 1; i <= 3; i++) {
for (var j:int = 1; j <= 2; j++) {
trace(i + " X " + j + " = " + (i * j));
}
}
1 X 1 = 1
1 X 2 = 2
2 X 1 = 2
2 X 2 = 4
3 X 1 = 3
3 X 2 = 6
进行多重嵌套的for 语句:
for (var i:int = 1; i <= 3; i++) {
for (var j:int = 1; j <= 3; j++) {
for (var k:int = 1; k <= 3; k++) {
trace(i + " X " + j + " X " + k + " = " + (i * j * k));
}
}
}
许多开发都错误的用 for 语句让sprites运动起来; 比如:
for (var i:int = 0; i < 20; i++) {
_sprite.x += 10;
}
上面的代码让sprite 向右移动200 像素,所有的更新都在同一帧完成,会出现两个问题:第一,场
景每帧更新一次,所以只有最后的更新显示在场景中(导致我们看到好像是直接跳过200像素,而
不是20 步内慢慢移动过去)。第二,即时场景不停更新,但是for 循环只需要几位秒,这样的动画
也太快了。因此正确的做法是把动画放到 enterFrame 事件上执行。
再者若循环的代码执行时间超过15秒,Flash播放器就会提示警告。
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 23 页 共 34 页
1.12. 长时间执行一个任务
问题
我要长时间执行一个任务
解决办法
使用 Timer 类,或者监听 sprite 的 enterFrame 事件
讨论
Timer 类是ActionScript 3.0新增的, 来代替早期的 setInterval( ) 和 setTimeout( ) 函数。当创建
Timer 类的实例时,它会在每个时间间隔激活 timer 事件,你可以在事件之间指定延时,然后就有
足够的时间去激活 Timer 构造器了:
var timer:Timer = new Timer(delay, repeatCount);
使用 addEventListener 来设置一个函数处理这个事件,然后使用timer 的 start( ) 方法启动或
stop( ) 停止它。
Timer 类属于 flash.utils 包,还有 TimerEvent 类在 flash.events 包中,因此需要导入它们:
package {
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class ExampleApplication extends Sprite {
private var _PreviousTime:Number = 0;
public function ExampleApplication( ) {
var tTimer:Timer = new Timer(500, 10);
tTimer.addEventListener(TimerEvent.TIMER, onTimer);
tTimer.start( );
}
private function onTimer(event:TimerEvent):void {
trace(flash.utils.getTimer( ) - _PreviousTime);
_PreviousTime = flash.utils.getTimer( );
}
}
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 24 页 共 34 页
getTimer( ) 函数已经被移动到flash.utils 包中了。它返回程序开始有到现在的相对时间(微妙)
上个例子中,事件每隔5毫秒激活一次。如果你想模拟setInterval( ) 函数,把重复次数设为0。 stop( )
方法类似于clearInterval( ) 函数,停止定时器.
如果想模拟 setTimeout( ) 函数,设置重复数为1,定时器等到指定时间激活一次事件,然后停止。
Timer 类最好的用处就是创建动画而不依赖于影片帧速。看下面的例子,两个定时器时间间隔分别
为50 微妙和100微妙:
package {
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class ExampleApplication extends Sprite {
private var _square:Sprite;
private var _circle:Sprite;
public function ExampleApplication( ) {
// 创建两个图形
_square = new Sprite( );
_square.graphics.beginFill(0xff0000);
_square.graphics.drawRect(0, 0, 100, 100);
_square.graphics.endFill( );
addChild(_square);
_square.x = 100;
_square.y = 50;
_circle = new Sprite( );
_circle.graphics.beginFill(0x0000ff);
_circle.graphics.drawCircle(50, 50, 50);
_circle.graphics.endFill( );
addChild(_circle);
_circle.x = 100;
_circle.y = 200;
// 创建两个定时器,启动
var squareTimer:Timer = new Timer(50, 0);
squareTimer.addEventListener(TimerEvent.TIMER, onSquareTimer);
squareTimer.start( );
var circleTimer:Timer = new Timer(100, 0);
circleTimer.addEventListener(TimerEvent.TIMER, onCircleTimer);
circleTimer.start( );
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 25 页 共 34 页
// 定义两个事件句柄
private function onSquareTimer(event:TimerEvent):void {
_square.x++;
}
private function onCircleTimer(event:TimerEvent):void {
_circle.x++;
}
}
}
当然用enterFrame 事件也可以实现的,但Timer 技术更加灵活。
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 26 页 共 34 页
1.13. 创建可重用代码
问题
我要实现代码重用,而不是每次都去复制同样的代码。
解决办法
创建一个方法,然后再需要的地方调用它,类中的函数 我们通常称为方法。
怎样创建类方法:
控制修饰符 function 方法名 ( ):返回数据类型 {
// 代码块
}
调用该方法只要饮用方法名就可以了,比如:
方法名( );
讨论
方法中的代码可以被多次执行。当你需要在不同的时间不同的地方执行同一个任务时就会很有用。
把代码放在方法既便于理解又便于维护,而不用再多个地方修改。
像类变量一样,方法也有访问控制符。修饰符有:
private
只能被自身类访问。
protected
能被自身类实例或子类实例访问,其他类实例不能访问。
internal
可以被所在包中的所有类实例访问。
public
可被任何类访问。
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 27 页 共 34 页
如果都没指定修饰符,默认为internal。下面的代码定义了一个画线方法,然后被调用10 次。
package {
import flash.display.Sprite;
public class ExampleApplication extends Sprite
{
public function ExampleApplication( ) {
for(var i:int=0;i<10;i++) {
drawLine( );
}
}
private function drawLine( ):void {
graphics.lineStyle(1, Math.random( ) * 0xffffff, 1);
graphics.moveTo(Math.random( ) * 400, Math.random( ) * 400);
graphics.lineTo(Math.random( ) * 400, Math.random( ) * 400);
}
}
}
还有种种要的方法类型是静态方法,静态方法不属于类实例,可以通过类直接调用静态方法。比如,
有个类叫ExampleApplication, 定义了静态方法:
public static function showMessage( ):void {
trace("Hello world");
}
可以这样调用:
ExampleApplication.showMessage( );
有些类只有静态方法,Math类就是个例子,注意我们使用Math方法时并没有创建类实例,我们只
是调用了类属性那样调用类方法,比如Math.random( ), Math.round( ), 等等
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 28 页 共 34 页
1.14. 增强代码可重用能力
问题
每次执行的任务都有微小的变化,但我又不想每次都复制那些代码修改一次。
解决办法
给方法传递参数让它适应不同的情况。
private function average (a:Number, b:Number, c:Number):void {
trace("The average is " + (c + b + c)/3);
}
讨论
比如你有个求一系列数的平均数函数average( ) ,你就可以把这些数字作为参数传递给函数去计算,
而不必每次都去重写average( )函数。
通常把参数都列在申明函数的括号内,多个参数用逗号分开。
下面有个简单的带有参数的函数申明:
//定义函数,带有两个参数: a 和 b.
private function average(a:Number, b:Number):Number {
return (a + b)/2;
}
//当函数被调用时,参数被传递进来,比如 5 和 11,
//被传递给了 a 和 b
var averageValue:Number = average(5, 11);
大多数情况下,方法参数的个数可以预料的,但是有些情况下参数的个数是事先不确定的。比如:
如果你想要让average( ) 方法接受任何数量的值,这时可以使用内建的数组,所有的参数都被放入
函数数组中。
// arguments 数组
private function average( ):Number {
var sum:Number = 0;
for (var i:int = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum/arguments.length;
}
// 像下面这样传递任意数量的参数:
var average:Number = average (1, 2, 5, 10, 8, 20);
arguments 是一个array对象。
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 29 页 共 34 页
1.15. 从方法中退出
问题
我要从方法中退出
解决办法
方法中的代码被执行完就会自动退出,也可使用return 语句直接退出。
讨论
return 语句将导致方法立即退出,ActionScript 解释器继续执行调用方法的所在位置的下面代码。
方法中return下面的语句将被忽略。
private function sampleFunction ( ):void {
return;
trace("Never called");
}
下面的代码展示如果密码是错误的,则从方法中退出:
private function checkPassword (password:String):void {
// 如果密码不是"SimonSays", 退出方法
if (password != "SimonSays") {
return;
}
//否则执行剩余的代码
showForm ("TreasureMap");
}
// 使用错误的密码调用函数,所以函数退出
checkPassword("MotherMayI");
//使用正确的密码,所以显示“TreasureMap”信息.
checkPassword("SimonSays");
你可能注意到上面的例子方法被申明为void, 如果用return 语句只是简单的退出这时可以的,但如
果想返回值得话编译器就会报错了,如:
private function sampleMethod ( ):void {
return "some value"; // This causes the compiler to generate an error.
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 30 页 共 34 页
1.16. 获得方法的执行结果
问题
我想执行一些方法,然后返回结果给调用它的函数
解决办法
使用 return 语句返回结果
讨论
return 返回的数据类型必须与函数申明的返回类型相一致。
private function average (a:Number, b:Number):Number {
return (a + b)/2;
}
现在我们调用 average( ) 方法 然后把返回结果存到变量中,然后使用这个变量:
var playerScore:Number = average(6, 10);
trace("The player's average score is " + playerScore);
也可以不通过变量:
trace("The player's average score is " + average(6, 10));
注意,如果你不处理返回的值,那么返回结果就是丢失掉:
average(6, 10);
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 31 页 共 34 页
1.17. 处理错误
问题
我想让程序自己检测和处理遇到的错误。
解决办法
当检测到错误时使用 throw 语句抛出异常。把可能出现错误的代码都放到 try 块中,然后在catch
块中进行错误处理。
讨论
Flash 播放器 8.5 开始支持 try/catch 方法来处理错误。这意味着可以灵活的处理遇到的错误了。
除了语法错误(这时编译器就通不过),其他类型的错误如非法数据等都可以自己处理。
处理异常包括两个部分,抛出异常和捕获异常。有些异常系统会自动抛出,比如 IllegalOperationError,
MemoryError, 和 ScriptTimeoutError. 它们都在 flash.errors 包中。除了系统定义的错误外也可以
抛出自定义错误,然后捕获它进行处理。使用 throw 语句抛出一个Error 对象或Error 子类实例,
比如:
throw new Error("A general error occurred.");
正如我们看到的,Error 构造器接受一个参数,这个信息和这个错误相关联。这个参数是可选的,
依赖于你怎样处理这个错误,你可以不使用,但是大多数情况下都指定一个错误信息作为调试目的。
一旦异常被抛出,Flash 就会暂停当前进程去寻找 catch 块去处理异常。任何有潜在错误的代码都
要放在 try 块中,如果异常抛出,只有它所在的 try 块被暂停,然后相关联的 catch 块被调用,看
下面的例子:
try {
trace("This code is about to throw an error.");
throw new Error("A general error occurred.");
trace("This line won't run");
}
catch (errObject:Error) {
trace("The catch block has been called.");
trace("The message is: " + errObject.message);
}
上面的代码数出以下信息:
This code is about to throw an error.
The catch block has been called.
The message is: A general error occurred.
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 32 页 共 34 页
当然,上面的代码还是过于简单,但是这是个基本框架,可以看到只要抛出异常,try 块就会退出,
catch 块被执行,传递了一个 Error 对象给 catch.
更多情况下,异常是从函数或方法中抛出的,Flash 会检测该函数是否在 try 块内被调用,如果是,
则调用相应的 catch 块。
private function displayMessage(message:String):void {
if(message == undefined) {
throw new Error("No message was defined.");
}
trace(message);
}
try {
trace("This code is about to throw an error.");
displayMessage( );
trace("This line won't run");
}
catch (errObject:Error) {
trace("The catch block has been called.");
trace("The message is: " + errObject.message);
}
上面的代码输出以下内容:
This code is about to throw an error.
The catch block has been called.
The message is: No message was defined.
如果你不肯定你的函数或方法会在何时或如何抛出异常,这时就应该在try块进行调用。
// 定一个在指定的sprite里的画矩形函数。
private function drawRectangle(sprite:Sprite, newWidth:Number, newHeight:Number):void {
// 检测长和宽的数值是否合法,否则抛出异常。
if(isNaN(newWidth) || isNaN(newHeight)) {
throw new Error("Invalid dimensions specified.");
}
// 如无异常,则画出矩形
sprite.graphics.lineStyle(1, 0, 1);
sprite.graphics.lineTo(nWidth, 0);
sprite.graphics.lineTo(nWidth, nHeight);
sprite.graphics.lineTo(0, nHeight);
sprite.graphics.lineTo(0, 0);
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 33 页 共 34 页
现在我们在 try/catch 语句内调用该函数。
try {
drawRectangle(this, widthB, heightB);
}
catch(errObject:Error) {
this.graphics.clear( );
tOutput.text = "An error occurred: " + errObject.message;
}
另外对于try/catch 语句,还可以加入 finally 块,finally 块包含的代码无论是否遇到异常都会被执
行。例如下面的两个例子效果相同:
//没有使用finally:
private function displayMessage(message:String):void {
try {
if(message == undefined) {
throw new Error("The message is undefined.");
}
trace(message);
}
catch (errObject:Error) {
trace(errObject.message);
}
trace("This is the last line displayed.");
}
//使用 finally:
private function displayMessage(message:String):void {
try {
if(message == undefined) {
throw new Error("The message is undefined.");
}
trace(message);
}
catch (errObject:Error) {
trace(errObject.message);
}
finally {
trace("This is the last line displayed.");
}
}
ActionScript 3 Cookbook 中文版
第一章. ActionScript 语言基础
第 34 页 共 34 页
如果在catch 中使用了return语句,那结果就不一样了:
//没有使用finally:
private function displayMessage(message:String):void {
try {
if(message == undefined) {
throw new Error("The message is undefined.");
}
trace(message);
}
catch (errObject:Error) {
trace(errObject.message);
return;
}
// 这一句没有执行.
trace("This is the last line displayed.");
}
//使用 finally:
private function displayMessage(message:String):void {
try {
if(message == undefined) {
throw new Error("The message is undefined.");
}
trace(message);
}
catch (errObject:Error) {
trace(errObject.message);
return;
}
finally {
// 执行,不管是否有异常发生。
trace("This is the last line displayed.");
}
}
通过这一节的学习,现在你可以建立复杂的异常处理系统。

2007年8月9日 @ 08:18

ActionScript 3 Cookbook 中文版 第五章.数组

ActionScript 3 Cookbook 中文版
第五章.数组
第 1 页 共 31 页
第五章.数组
5.0.简介
5.1.在数组首部和尾部添加元素
5.2.遍历数组成员
5.3.搜索匹配的数组元素
5.4.删除数组元素
5.5.在数组中间插入元素
5.6.转换字符串为数组
5.7.转换数组为字符串
5.8.创建数组的拷贝
5.9.存储多维数据
5.10.数组排序
5.11.实现自定义排序
5.12.数组元素的随机排序
5.13.取得数组元素的最大值和最小值
5.14.比较数组
5.15.创建联合数组
5.16.读取联合数组
ActionScript 3 Cookbook 中文版
第五章.数组
第 2 页 共 31 页
5.0. 简介
数组保存一组相关联的数据,组织和处理这些数据。数组概念在生活中是很常见的,比如菜谱,包
含姓名,地址,生日等地址本都是数组原理。
在ActionScript 中,有两种数组:整型下标和联合数组,都是组织相关数据,只是访问数据的方法
不同而已。
整型下标数组:
数组的每个元素都用唯一的整数下标来索引。通过下标排序,起始值为0,每个元素保存在索引指
定的位置,这就像抽屉一样。
联合数组 :
用字符串关键字作为每个元素的索引。
首先创建数组,有两种构造方法,
// 创建空的数组
var array:Array = new Array();
// 创建数组时指定数组长度
var array:Array = new Array(elements);
//创建数组时加入多个元素
var array:Array = new Array(element0,...elementN);
直接用数组符号也可以创建一个数组,这是很简洁的方式创建数组:
var letters:Array = ["a", "b", "c"];
Array 类提供了一些方法修改数组内容或者返回新的数组
使用数组操作符(中括号加上下标索引)来读取和设置内容,如:
//设置第5个元素为"apples"
// (下标从0开始).
items[4] = "apples";
// 显示第5个元素
trace(items[4]); // 显示: apples
ActionScript 并不关心数组里存的是什么类型的数据,可以是字符串,数字,布尔值和引用的类型,
而且不像其他语言,同一个数组可以存不同类型的数据,例如:
var data:Array = ["a", 2, true, new Object()];
还有点不同,数组在创建时可以不用指定数组长度。
ActionScript 3 Cookbook 中文版
第五章.数组
第 3 页 共 31 页
5.1. 在数组首部和尾部添加元素
问题
我要再添加新元素到数组
解决办法
push( ) 方法在数组尾部添加元素,unshift( ) 方法在数组首部插入元素
讨论
Array.push( ) 方法把元素加在数组的尾部,也可以一次添加多个值:
var array:Array = new Array();
array.push("val 1", "val 2");
也可以在数组指定的下标位置设置值,下标位置在0到Array .length - 1 之间:
array[array.length] = "val 3";
如果下标不存在,数组会自动扩充,扩充的空间当中,没有被赋值的自动以"undefined"填充:
var letters:Array = ["a", "b", "c"];
letters[5] = "f";
通过unshift( ) 方法在数组首部插入新元素:
// 创建四个元素的数组
// "a", "b", "c", "d".
var letters:Array = new Array( );
letters.push("a", "b", "c", "d");
// 添加"z" ,其他元素依次向下移动
letters.unshift("z");
for (var i:int = 0; i < letters.length; i++) {
trace(letters[i]);
}
到底把数据插入到哪里需要根据具体实际需要,比如要达到(LIFO) 目的,我们需要 Array.push( ) 和
Array.pop( ) 成对使用。
ActionScript 3 Cookbook 中文版
第五章.数组
第 4 页 共 31 页
5.2. 遍历数组成员
问题
我要访问数组的每个元素
解决办法
利用 for 循环来遍历数组,使用下标返回元素。
讨论
for 循环的初始变量从0开始,结束为array.length-1,因为是从下标0开始的:
var letters:Array = ["a", "b", "c"];
for (var i:int = 0; i < letters.length; i++) {
trace("Element " + i + ": " + letters[i]);
}
也可以降序遍历数组,循环变量从array.length-1开始到0:
var letters:Array = ["a", "b", "c"];
for (var i:int = letters.length - 1; i >= 0; i--){
trace("Element " + i + ": " + letters[i]);
}
有很多情况需要用循环遍历所有元素,比如,获得了包含sprite的数组, 然后把每个sprite 的x坐标
+1:
for (var i:int = 0; i < sprites.length; i++){
sprites[i].x++;
}
可以把数组长度存在变量中,免得每次循环都要重新计算:
var length:int = sprites.length;
for (var i:int = 0; i < length; i++){
sprites[i].x++;
}
这样做可以提高Flash 性能,因为不用每次循环都去计算长度了,但是有个前提,就是没有进行插
入删除操作来改变长度值,否则就要每次计算长度才行。
ActionScript 3 Cookbook 中文版
第五章.数组
第 5 页 共 31 页
5.3. 搜索匹配的数组元素
问题
我要找出指定值得数组元素
解决办法
用for 语句和break 语句就能找到匹配的元素。另外用ArrayUtilities.findMatchIndex( ),
ArrayUtilities.findLastMatchIndex( ), 和ArrayUtilities.findMatchIndices( ) 方法
讨论
用for 循环查找第一个匹配的元素后,用break 立即返回,这样就实现功能了。
break 应该在if 语句里进行判断,是否找到匹配元素,找到则执行break 推出循环,否则继续查找。
var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
// 指定要搜索的内容
var match:String = "b";
for (var i:int = 0; i < letters.length; i++) {
// 检测当前元素是否匹配
if (letters[i] == match) {
trace("Element with index " + i +
" found to match " + match);
break;
}
}
也可以找到匹配的最后一个元素,这就需要倒序遍历数组:
var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
var match:String = "b";
for (var i:int = letters.length - 1; i >= 0; i--) {
if (letters[i] == match) {
trace("Element with index " + i +
" found to match " + match);
break;
}
}
ActionScript 3 Cookbook 中文版
第五章.数组
第 6 页 共 31 页
使用自定义类ArrayUtilities 类更简单,它在 ascb.util 包中,首先导入它:
import ascb.util.ArrayUtilities;
ArrayUtilities 类有三个方法来查找匹配的元素findMatchIndex( ), findLastMatchIndex( ), 和
findMatchIndices( )。 findMatchIndex( ) 方法至少需要两个参数:一个指向数组的引用和需要匹配
的值,返回第一个匹配的元素下标,如果找不到返回-1:
var letters:Array = ["a", "b", "c", "d"];
trace(ArrayUtilities.findMatchIndex(letters, "b"));
// 显示: 1
trace(ArrayUtilities.findMatchIndex(letters, "r"));
// 显示: -1
也可以指定搜索的起始下标作为第三个参数:
var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
trace(ArrayUtilities.findMatchIndex(letters, "a", 1));
// 显示: 4
如果第三个参数为true,则返回部分匹配的元素:
var words:Array = ["bicycle", "baseball", "mat", "board"];
trace(ArrayUtilities.findMatchIndex(words, "s", true));
// 显示: 1
如果你想部分匹配又想指定起始搜索下标,可以把起始下标作为第四个参数。
findLastMatchIndex( ) 方法返回最后一个匹配的元素下标
findMatchIndices( ) 方法返回所有匹配的元素下标数组:
var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
trace(ArrayUtilities.findMatchIndices(letters, "b"));
// 显示: 1,5
也可以设定为部分匹配,指定第三个参数为true:
var words:Array = ["bicycle", "baseball", "mat", "board"];
trace(ArrayUtilities.findMatchIndices(words, "b", true));
// 显示: 0,1,3
ActionScript 3 Cookbook 中文版
第五章.数组
第 7 页 共 31 页
ArrayUtilities 方法内部也是用for 循环来实现的,现在我们看看代码,下面是findMatchIndex( ) 方
法的代码:
public static function findMatchIndex(array:Array, element:Object):int {
// Use a variable to determine the index
// from which to start. Use a default value of 0.
var startingIndex:int = 0;
// By default don't allow a partial match.
var partialMatch:Boolean = false;
// If the third parameter is a number,
// assign it to nStartingIndex.
// Otherwise, if the fourth parameter is a number,
// assign it to nStartingIndex instead.
if(typeof arguments[2] == "number") {
startingIndex = arguments[2];
}
else if(typeof arguments[3] == "number") {
startingIndex = arguments[3];
}
// If the third parameter is a Boolean value,
// assign it to partialMatch.
if(typeof arguments[2] == "boolean") {
partialMatch = arguments[2];
}
// Assume no match is found.
var match:Boolean = false;
// Loop through each of the elements of the array
// starting at the specified starting index.
for(var i:int = startingIndex;
i < array.length; i++) {
// Check to see if the element either matches
// or partially matches.
if(partialMatch) {
match = (array[i].indexOf(element) != -1);
}
else {
match = (array[i] == element);
}
// If the element matches, return the index.
ActionScript 3 Cookbook 中文版
第五章.数组
第 8 页 共 31 页
if(match) {
return i;
}
}
// The following return statement is only reached
// if no match was found. In that case, return -1.
return -1;
}
public static function findMatchIndices(array:Array,
element:Object, partialMatch:Boolean = false):Array {
var indices:Array = new Array( );
var index:int = findMatchIndex(array,
element,
partialMatch);
while(index != -1) {
indices.push(index);
index = findMatchIndex(array,
element,
partialMatch,
index + 1);
}
return indices;
}
ActionScript 3 Cookbook 中文版
第五章.数组
第 9 页 共 31 页
5.4. 删除数组元素
问题
我要删除一个或多个数组元素,或移动数组元素
解决办法
splice( ) 方法删除指定位置的元素,pop( ) 删除尾部元素,shift( ) 删除首部元素
讨论
删除指定位置的元素使用splice( ) 方法,它需要两个参数:
start
开始下标
deleteCount
删除的元素个数,如果没有定义,则从起始位置到末尾全部删除:
var letters:Array = ["a", "b", "c", "d"];
//从下标1开始删除1个元素
letters.splice(1, 1);
// 显示结果,现在只剩三个
// "a", "c", 和 "d".
for (var i:int = 0; i < letters.length; i++) {
trace(letters [i]);
}
splice( ) 方法也返回一个新的包含删除的元素数组:
var letters:Array = ["a", "b", "c", "d"];
//删除两个元素,从0位置开始
var deleted:Array = letters.splice(0, 2);
// 显示: "a","b".
for (var i:int = 0; i < deleted.length; i++) {
trace(deleted[i]);
}
删除首部和尾部的元素可用shift( ) 和pop( ) 方法。 shift( ) 方法删除首部第一个元素,然后返回该
元素,pop( ) 方法删除尾部的元素并返回该值:
var letters:Array = ["a", "b", "c", "d"];
trace(letters.shift( ));
trace(letters.pop( ));
//显示剩下的元素
for (var i = 0; i < letters.length; i++) {
trace(letters[i]);
}
ActionScript 3 Cookbook 中文版
第五章.数组
第 10 页 共 31 页
在for 循环里删除原始,也要修改下标值,下面的代码演示不更新下标值变量出现的情况:
var numbers:Array = new Array(4, 10);
numbers[4] = 1;
trace(numbers); // 显示: 4,10,undefined,undefined,1
for(var i:int = 0; i < numbers.length; i++) {
if(numbers[i] == undefined) {
numbers.splice(i, 1);
}
}
trace(numbers); // 显示: 4,10,undefined,1
上面的代码本来是期望上出全部undefined 元素的,结果只删除一个,调试运行,看看发生了什么:
1。前两个循环什么都没做,因为都不是undefined.
2。第三次找到 undefined 然后删除它,这时,第4个和第5个元素下移变成了第3个和第4个元

3。下一循环检测第4 个元素,也就是最后一个,这时忽略了第3 个元素也就是那个undefined 元
素,因此,当删除元素,应该把小标变量-1,代码应该这样:
var numbers:Array = new Array(4, 10);
numbers[4] = 1;
trace(numbers); // 显示: 4,10,undefined,undefined,1
for(var i:int = 0; i < numbers.length; i++) {
if(numbers[i] == undefined) {
numbers.splice(i, 1);
i--;
}
}
trace(numbers); // 显示: 4,10,1
ActionScript 3 Cookbook 中文版
第五章.数组
第 11 页 共 31 页
5.5. 在数组中间插入元素
问题
我要在数组中间插入元素u
解决办法
使用splice( ) 方法
讨论
splice( ) 方法不仅可以删除元素,也可以插入元素,插入的元素放到第2个参数之后,当第2个参
数为0代表插入元素:
var letters:Array = ["a", "b", "c", "d"];
//插入三个元素,起始位置为1
letters.splice(1, 0, "r", "s", "t");
// letters 现在包含的元素有:
// "a", "r", "s", "t", "b", "c", "d".
for (var i:int = 0; i < letters.length; i++) {
trace(letters[i]);
}
你也可以删除和插入同时执行:
var letters:Array = ["a", "b", "c", "d"];
//删除2个,插入3个
letters.splice(1, 2, "r", "s", "t");
// myArray 现在的元素
// "a", "r", "s", "t", and "d".
for (var i:int = 0; i < letters.length; i++) {
trace(letters[i]);
}
ActionScript 3 Cookbook 中文版
第五章.数组
第 12 页 共 31 页
5.6. 转换字符串为数组
问题
我有一堆字符串,想把它转换为数组。
解决办法
使用String.split( ) 方法
讨论
String 类的split( ) 方法把字符串转换为数组,但前提是字符串中含有统一的分割符,比如
Susan,Robert,Paula 字符串分割符为逗号
split( ) 方法接受两个参数:
分割符
用分割符来分割字符串,如果没定义,则把整个字符串作为数组的第一个元素
数量
分割出的最大元素个数,如果没定义,则全部放入数组。
可以使用空格符作为分割符:
var list:String = "Peter Piper picked a peck of pickled peppers";
var words:Array = list.split(" ");
split( ) 方法在用URLLoader 对象读取数据时经常用到,比如你接受服务器的一些姓名字符串:
names=Michael,Peter,Linda,Gerome,Catherine
这是用split( ) 方法转换为数组:
// URLLoader 读取数据
var namesData:String = _loader.data;
var names:Array = namesData.split(",");
ActionScript 3 Cookbook 中文版
第五章.数组
第 13 页 共 31 页
5.7. 转换数组为字符串
问题
我要把数组转换为字符串
解决办法
使用 join( ) 方法
讨论
ActionScript 提供内建的方法 join( ) 可以快速把数组转换为字符串(数组中的元素不管什么类型都
将转换为字符串),该方法接受个参数作为分隔符:
var letters:Array = ["a", "b", "c"];
trace(letters.join("|")); // 显示: a|b|c
如果不指定分隔符,默认为逗号:
var letters:Array = ["a", "b", "c"];
trace(letters.join()); // 显示: a,b,c
当 join( ) 的分隔符为逗号,其效果和toString( ) 一样。实际上当我们直接输出数组时系统就是调用
toString( ) 方法进行转换的,例如:
var letters:Array = ["a", "b", "c"];
trace(letters); // 显示: a,b,c
ActionScript 3 Cookbook 中文版
第五章.数组
第 14 页 共 31 页
5.8. 创建数组的拷贝
问题
我要复制一份数组,内容完全一样,只是不同的引用
解决办法
使用 concat( ) 方法或 slice( ) 方法,另外还可以使用ArrayUtilities.duplicate( ) 方法,duplicate( )
方法可以创建递归复制
讨论
因为数组是复合类型,因此它的比较和复制都和基本类型不同。一个变量指向数组但是实际上它并
不包含数组数据,它只是指向内存中存放数组数据的位置。从优化的角度考虑,基本类型的占用空
间往往很小,但是符合类型如数组可以变得很大,如果我们在日常操作中经常复制整个数组是非常
不明智的,因此当你要复制数组时,ActionScript 并不是生成独立的一份拷贝,看下面的例子:
首先我们看看基本类型是怎么复制的:
// 赋值数字5给变量
var quantity:int = 5;
// 拷贝 quantity的值 给另一个变量 newQuantity.
var newQuantity:int = quantity;
// 改变 quantity的值
quantity = 29;
trace(quantity); // 显示: 29
trace(newQuantity); // 显示: 5
我们看到,两者是互不影响的,也就是说基本变量拷贝的是值
现在我们看看数组的操作,和上面的例子不同,两个变量实际上都指向了同一个数组存贮空间。当
letters 变量改变数组内容时,也影响到newLetters 变量:
// 赋值数组.
var letters:Array = ["a", "b", "c"];
// 拷贝 letters 到newLetters.
var newLetters:Array = letters;
// 两个数组包含相同内容
trace(letters); // 显示: "a,b,c"
trace(newLetters); // 显示: "a,b,c"
// 改变letters的值
letters = ["d", "e", "f"];
// 另一个数组也变了
trace(letters); // 显示: "d,e,f"
trace(newLetters); // 显示: "d,e,f" (而不是 "a,b,c")
ActionScript 3 Cookbook 中文版
第五章.数组
第 15 页 共 31 页
其实这就像文件夹的两个快捷方式那样,两个快捷方式虽然名字不同,但是都指向同一个文件,无
论哪个对文件夹操作,另一个快捷方式也发生变化。
如果真要复制数组,可以调用数组的 concat( ) 方法:
// 给数组赋值.
var letters:Array = ["a", "b", "c"];
//用concat( ) 创建新的数组
var newLetters:Array = letters.concat( );
// 两个数组内容一样
trace(letters); // 显示: "a,b,c"
trace(newLetters); // 显示: "a,b,c"
// 改变letters的值
letters = ["d", "e", "f"];
//不像上面的例子,这次两个数组内容不同了.
trace(letters); // 显示: "d,e,f"
trace(newLetters); // 显示: "a,b,c"
也可以用 slice( ) 方法代替 concat( ), 例如:
var newLetters:Array = letters.slice(0);
concat( ) 或 slice( ) 方法复制一维整型下标的数组还可以,但是如果是多维的联合数组就不行了,
对于联合数组,不能使用 concat( ) 或 slice( ) 方法,对于多维数组,用 concat( ) 或 slice( ) 只能
复制顶层的数组,内部的就不能复制了,看下面的代码:
var coordinates:Array = new Array( );
coordinates.push([0,1,2,3]);
coordinates.push([4,5,6,7]);
coordinates.push([8,9,10,11]);
coordinates.push([12,13,14,15]);
// 复制
var coordinatesDuplicate:Array = coordinates.concat( );
// 替换元素
coordinatesDuplicate[0][0] = 20;
trace(coordinates[0][0]); //显示: 20
// 替换顶层元素.
coordinatesDuplicate[1] = [21,22,23,24];
trace(coordinates[1]); // 显示: 4,5,6,7
上面的代码coordinates 是个二维数组,coordinatesDuplicate 是coordinates的复制。但是,虽然
是复制,有些元素仍然引用了原始数组元素,这就意味你改变了一个,会影响另一个数组的内容。
实际上从上面的代码可以看出,只复制了顶层的数组,这一部分是互不关联的。
ActionScript 3 Cookbook 中文版
第五章.数组
第 16 页 共 31 页
要想完全的复制数组,需要使用递归。ArrayUtilities.duplicate( ) 方法就是这样的做法,默认下它也
只复制一层数组,当第2个参数设为true时则是递归复制:
// 创建二维数组
var coordinates:Array = new Array( );
for(var i:int = 0; i < 4; i++) {
coordinates[i] = new Array( );
for(var j:int = 0; j < 4; j++) {
coordinates[i].push(String(i) + "," + String(j));
}
}
// 复制coordinates.
var newCoordinates:Array = ArrayUtilities.duplicate(coordinates, true) as Array;
// 替换
newCoordinates[0][0] = "a";
// 使用toString() 方法输出
trace(ArrayUtilities.toString(coordinates));
trace(ArrayUtilities.toString(newCoordinates));
下面的例子演示用 duplicate( ) 方法复制联合数组:
var coordinatesMap:Object = new Object( );
coordinatesMap.a = [{a: 1},{b: 2}, {c: 3}, {d: 4}];
coordinatesMap.b = [{a: 1},{b: 2}, {c: 3}, {d: 4}];
coordinatesMap.c = [{a: 1},{b: 2}, {c: 3}, {d: 4}];
coordinatesMap.d = [{a: 1},{b: 2}, {c: 3}, {d: 4}];
var newCoordinatesMap:Object = ArrayUtilities.duplicate(coordinatesMap, true);
newCoordinatesMap.a[0] = {r: 5};
trace(ArrayUtilities.toString(coordinatesMap));
trace(ArrayUtilities.toString(newCoordinatesMap));
两个例子可以看到,复制的数组改变不会影响原始数组。
ActionScript 3 Cookbook 中文版
第五章.数组
第 17 页 共 31 页
5.9. 存储多维数据
问题
我要怎样存储多组相关的数据
解决办法
使用多维数组存储
讨论
除了一维数组,还可以创建多维数组,比如 beginGradientFill() 方法(在第7章讨论)使用三个平
行数组表示colors, alphas, 和ratios ,每个数组都有相同的下标。
创建平行数组,然后操作同一下标的元素,使用平行数组,很容易访问同一下标的相关元素,比如:
var colors:Array = ["maroon", "beige", "blue", "gray"];
var years:Array = [1997, 2000, 1985, 1983];
var makes:Array = ["Honda", "Chrysler", "Mercedes", "Fiat"];
// 循环这些数组,因此数组的长度相同,可以用任何一个数组的length 属性,下面的例子使用了
//makes.length.
for (var i:int = 0; i < makes.length; i++) {
trace("A " + colors[i] + " " +
years[i] + " " +
makes[i]);
// 显示:
// A maroon 1997 Honda
// A beige 2000 Chrysler
// A blue 1985 Mercedes
// A gray 1983 Fiat
}
需要注意的是,如果改变了数组长度,必须同时修改其他数组。
ActionScript 3 Cookbook 中文版
第五章.数组
第 18 页 共 31 页
另一种方法就是创建多维数组,它是数组的数组:
// 创建数组 cars,然后用数组组装填充,每个元素都是数组包含3个元素 (color, year, make).
var cars:Array = new Array();
cars.push(["maroon", 1997, "Honda"]);
cars.push(["beige", 2000, "Chrysler"]);
cars.push(["blue", 1985, "Mercedes"]);
cars.push(["gray", 1983, "Fiat"]);
// 循环遍历数组
for (var i:int = 0; i < cars.length; i++) {
// 显示:
// A maroon 1997 Honda
// A beige 2000 Chrysler
// A blue 1985 Mercedes
// A gray 1983 Fiat
TRace("A " + cars[i][0] + " " +
cars[i][1] + " " +
cars[i][2]);
}
下面的代码用二重循环遍历二维数组:
for (var i:int = 0; i < cars.length; i++) {
for (var j:int = 0; j < cars[i].length; j++) {
TRace("Element [" + i + "][" + j + "] contains: " +
cars[i][j]);
}
}
从上面的例子来看,很难区别cars[i][0] 和 cars[i][j]。但如果任何数组的长度发生变化这时cars[i][0]
这种表示就很被动,需要修改代码才行。
另外对象数组的使用也很类似,只是多了个名称属性。对象数组用名称属性代替数字下标来索引元
素:
// 创建数组cars,填充对象
// 每个对象有个make 属性,year 属性和 color 属性
var cars:Array = new Array();
cars.push({make: "Honda", year: 1997, color: "maroon"});
cars.push({make: "Chrysler", year: 2000, color: "beige"});
cars.push({make: "Mercedes", year: 1985, color: "blue"});
cars.push({make: "Fiat", year: 1983, color: "gray"});
// 遍历数组
for (var i:int = 0; i < cars.length; i++) {
trace("A " + cars[i].color + " " +
cars[i].year + " " +
cars[i].make);
}
ActionScript 3 Cookbook 中文版
第五章.数组
第 19 页 共 31 页
5.10. 数组排序
问题
我要进行数组排序
解决办法
使用 sort( ) 方法,对于对象数组可以用 sortOn( ) 方法
讨论
使用 sort( ) 方法就可以对数组进行排序,没有参数是进行升序排序,对于字符内容采用 Unicode
编码排序
var words:Array = ["tricycle", "relative", "aardvark", "jargon"];
words.sort( );
trace(words); // 显示: aardvark,jargon,relative,tricycle
如果要进行降序排序,需要传递参数Array.DESCENDING 常量:
var words:Array = ["tricycle", "relative", "aardvark", "jargon"];
words.sort(Array.DESCENDING);
trace(words); // 显示: tricycle,relative,jargon,aardvark
上面的例子没有考虑大小写问题,比如:
var words:Array = ["Tricycle", "relative", "aardvark", "jargon"];
words.sort( );
trace(words); // 显示: Tricycle,aardvark,jargon,relative
使用Array.CASEINSENSITIVE 常量忽略大小写进行排序:
var words:Array = ["Tricycle", "relative", "aardvark", "jargon"];
words.sort(Array.CASEINSENSITIVE);
trace(words); // 显示 aardvark,jargon,relative,Tricycle
如果对数字内容的数组排序,则根据第一个数字的ASCII 排序:
var scores:Array = [10, 2, 14, 5, 8, 20, 19, 6];
scores.sort( );
trace(scores); // 显示: 10,14,19,2,20,5,6,8
ActionScript 3 Cookbook 中文版
第五章.数组
第 20 页 共 31 页
使用 Array.NUMERIC 常量才能正常对数字排序:
var scores:Array = [10, 2, 14, 5, 8, 20, 19, 6];
scores.sort(Array.NUMERIC);
trace(scores); // 显示:2,5,6,8,10,14,19,20
还有两个常量Array.UNIQUESORT 和 array.RETURNINDEXEDARRAY. ,如果你只是对含有唯一
元素的数组排序就可以用Array.UNIQUESORT ,Flash 只会对这样的数组排序,不满足条件 sort( )
返回0,且不进行排序:
var ranking:Array = [2,5,6,3,1,1,4,8,7,10,9];
var sortedRanking:Object = ranking.sort(Array.UNIQUESORT);
trace(sortedRanking); // 显示: 0
trace(ranking); // 显示:2,5,6,3,1,1,4,8,7,10,9
Array.RETURNINDEXEDARRAY 得到排序后数组元素的下标顺序,但不改变原始数组:
var words:Array = ["tricycle", "relative", "aardvark", "jargon"];
var indices:Array = words.sort(Array.RETURNINDEXEDARRAY);
trace(words); // 显示: tricycle,relative,aardvark,jargon
trace(indices); // 显示: 2,3,1,0
for(var i:int = 0; i < words.length; i++) {
/* 显示
aardvark
jargon
relative
tricycle
*/
trace(words[indices[i]]);
}
可以用操作符(|)联合使用这些常量:
var words:Array = ["Tricycle", "relative", "aardvark", "jargon"];
words.sort(Array.CASEINSENSITIVE | Array.DESCENDING);
trace(words); // 显示: Tricycle,relative,jargon,aardvark
有时候你想反转数组该怎么办呢?sort( ) 方法并没这功能,这是可以用 reverse( ) 方法:
var words:Array = ["tricycle", "relative", "aardvark", "jargon"];
words.reverse( );
trace(words); // 显示: jargon,aardvark,relative,tricycle
ActionScript 3 Cookbook 中文版
第五章.数组
第 21 页 共 31 页
上面的部分讨论了怎么对字符串和数字进行排序,对于对象数组可用 sortOn( ) 方法,该方法需要
一个字符串参数指定名称属性对其排序:
var cars:Array = new Array();
cars.push({make: "Honda", year: 1997, color: "maroon"});
cars.push({make: "Chrysler", year: 2000, color: "beige"});
cars.push({make: "Mercedes", year: 1985, color: "blue"});
cars.push({make: "Fiat", year: 1983, color: "gray"});
// 对 year 属性进行排序 cars.sortOn("year"):
for (var i:int = 0; i < cars.length; i++) {
/* 显示:
gray 1983 Fiat
blue 1985 Mercedes
maroon 1997 Honda
beige 2000 Chrysler
*/
trace(cars[i].color + "\t" +
cars[i].year + "\t" +
cars[i].make);
}
sortOn( ) 方法也可以一次对多个字段进行排序,看下面的代码:
var cars:Array = new Array( );
cars.push({make: "Honda", year: 1997, color: "maroon"});
cars.push({make: "Chrysler", year: 2000, color: "beige"});
cars.push({make: "Mercedes", year: 1985, color: "blue"});
cars.push({make: "Fiat", year: 1983, color: "gray"});
cars.push({make: "Honda", year: 1992, color: "silver"});
cars.push({make: "Chrysler", year: 1968, color: "gold"});
cars.push({make: "Mercedes", year: 1975, color: "green"});
cars.push({make: "Fiat", year: 1983, color: "black"});
cars.push({make: "Honda", year: 2001, color: "blue"});
cars.push({make: "Chrysler", year: 2004, color: "orange"});
cars.push({make: "Mercedes", year: 2000, color: "white"});
cars.push({make: "Fiat", year: 1975, color: "yellow"});
// 对两个字段排序
cars.sortOn(["year", "make"]);
for (var i:int = 0; i < cars.length; i++) {
/* 显示:
gold 1968 Chrysler
yellow 1975 Fiat
green 1975 Mercedes
black 1983 Fiat
gray 1983 Fiat
blue 1985 Mercedes
silver 1992 Honda
maroon 1997 Honda
ActionScript 3 Cookbook 中文版
第五章.数组
第 22 页 共 31 页
beige 2000 Chrysler
white 2000 Mercedes
blue 2001 Honda
orange 2004 Chrysler
*/
trace(cars[i].color + "\t" +
cars[i].year + "\t" +
cars[i].make);
}
下面的例子,先对 make, 再对year排序:
cars.sortOn(["make", "year"]);
for (var i:int = 0; i < cars.length; i++) {
/* 显示:
gold 1968 Chrysler
beige 2000 Chrysler
orange 2004 Chrysler
yellow 1975 Fiat
black 1983 Fiat
gray 1983 Fiat
silver 1992 Honda
maroon 1997 Honda
blue 2001 Honda
green 1975 Mercedes
blue 1985 Mercedes
white 2000 Mercedes
*/
trace(cars[i].color + "\t" +
cars[i].year + "\t" +
cars[i].make);
}
sortOn( ) 方法也可用那些数组常量完成降序,忽略大小写等排序:
cars.sortOn("year", Array.DESCENDING);
for (var i:int = 0; i < cars.length; i++) {
/* 显示:
beige 2000 Chrysler
maroon 1997 Honda
blue 1985 Mercedes
gray 1983 Fiat
*/
trace(cars[i].color + "\t" +
cars[i].year + "\t" +
cars[i].make);
}
ActionScript 3 Cookbook 中文版
第五章.数组
第 23 页 共 31 页
5.11. 实现自定义排序
问题
我要自定义数组排序
解决办法
把自定义比较的函数引用传递给sort( ) 方法
讨论
如果要自定义排序,可用sort( ) 方法和自定义比较函数。sort( ) 方法重复调用比较函数对两个数组
元素进行比较,比较函数接受两个参数即数组元素(我们称为a和b),根据具体的排序方式返回正
数,负数或0。如果返回负数,a排在b前,如果返回0,位置不变,如果返回正数,a排在b后,
直到所有元素对比完毕。
下面有个例子对字符串数组进行自定义排序,比如是一个歌曲名数组,在排序时忽略字符串中含有
的"The" 字母,首先看看默认的排序:
var bands:Array = ["The Clash",
"The Who",
"Led Zeppelin",
"The Beatles",
"Aerosmith",
"Cream"];
bands.sort( );
for(var i:int = 0; i < bands.length; i++) {
trace(bands[i]);
/* 输出:
Aerosmith
Cream
Led Zeppelin
The Beatles
The Clash
The Who
*/
}
给 sort( ) 方法传递bandNameSort 比较函数:
var bands:Array = ["The Clash",
"The Who",
"Led Zeppelin",
"The Beatles",
"Aerosmith",
"Cream"];
bands.sort(bandNameSort);
for(var i:int = 0; i < bands.length; i++) {
ActionScript 3 Cookbook 中文版
第五章.数组
第 24 页 共 31 页
trace(bands[i]);
/*输出
Aerosmith
The Beatles
The Clash
Cream
Led Zeppelin
The Who
*/
}
function bandNameSort(band1:String, band2:String):int
{
band1 = band1.toLowerCase( );
band2 = band2.toLowerCase( );
if(band1.substr(0, 4) == "the ") {
band1 = band1.substr(4);
}
if(band2.substr(0, 4) == "the ") {
band2 = band2.substr(4);
}
if(band1 < band2) {
return -1;
}
else {
return 1;
}
}
bandNameSort( ) 函数把字符串元素转换为小写,然后检测是否含有"The ",如果有则剪切掉,取
剩余字符串进行比较
ActionScript 3 Cookbook 中文版
第五章.数组
第 25 页 共 31 页
5.12. 数组元素的随机排序
问题
我要打乱数组元素的顺序
解决办法
使用 sort( ) 方法和自定义比较函数返回随机的正数或负数
讨论
很多情况我们需要得到一个随机排列的数组,比如有个游戏需要产生随机的字母。
有很多种方法达到这个目的,但是最简单的办法就是创建自定义比较函数,返回随机的正数或负数,
把该函数引用传递给sort( ) 方法:
下面的比较函数就能达到目的:
function randomSort(elementA:Object, elementB:Object):Number {
return Math.random( ) - .5
}
Math.random( ) 返回0.0 到 1.0. 减去0.5 ,正好有一半的几率是负数,一半为正数,因此这个数
组经过随机排序
看下面的随机排序例子:
var numbers:Array = new Array( );
for(var i:int=0;i<20;i++) {
numbers[i] = i;
}
numbers.sort(randomSort);
for(var i:int=0;i<numbers.length;i++) {
trace(numbers[i]);
}
ActionScript 3 Cookbook 中文版
第五章.数组
第 26 页 共 31 页
5.13. 取得数组元素的最大值和最小值
问题
我要获取数字数组的最大和最小元素
解决办法
经过数字排序,然后读取数组的第一个和最后一个元素
讨论
要想快速的取得最大值和最小值,先进行排序,看下面:
var scores:Array = [10, 4, 15, 8];
scores.sort(Array.NUMERIC);
trace("Minimum: " + scores[0]);
trace("Maximum: " + scores[scores.length - 1]);
如果不破坏原有数组顺序,可先复制数组:
也可使用 ArrayUtilities.min( ) 和 ArrayUtilities.max( ) 方法。
ActionScript 3 Cookbook 中文版
第五章.数组
第 27 页 共 31 页
5.14. 比较数组
问题
我该怎么知道两个数组是否相等呢
解决办法
循环数组,一一比较对应位置的每个元素
讨论
因为数组是引用类型,使用=操作符只能对比引用是否指向同一内存空间,如:
var letters:Array = ["a", "b", "c", "d"];
var lettersPointer:Array = letters;
trace(letters == lettersPointer); // 显示: true
但是如果数组内容相同,但是在不同的内存空间,=操作就会返回false:
var letters1:Array = ["a", "b", "c", "d"];
var letters2:Array = ["a", "b", "c", "d"];
trace(letters1 == letters2]; // 显示: false
因此,比较数组应该比较数组的每个元素是否相等:
var equivalent:Boolean = true;
for(var i:int = 0; i < letters1.length; i++) {
if(letters1[i] != letters2[i]) {
equivalent = false;
break;
}
}
trace(equivalent); // 显示: true
另外还可以用ArrayUtilities.equals( ) 方法,该方法需要两个参数:两个数组引用,返回布尔值说明
是否相等:
var letters1:Array = ["a", "b", "c", "d"];
var letters2:Array = ["a", "b", "c", "d"];
trace(ArrayUtilities.equals(letters1, letters2));
// 显示: true
ActionScript 3 Cookbook 中文版
第五章.数组
第 28 页 共 31 页
默认,两个不同排列的数组是不相等的,除非提供第3个参数为true 表示忽略数组排列顺序:
var letters1:Array = ["a", "b", "c", "d"];
var letters2:Array = ["b", "a", "d", "c"];
trace(ArrayUtilities.equals(letters1, letters2));
// 显示: false
trace(ArrayUtilities.equals(letters1, letters2, true));
// 显示: true
equals( ) 方法用起来很简单,下面是它的代码:
public static function equals(arrayA:Array,
arrayB:Array,
bNotOrdered:Boolean):Boolean {
// 如果两个数组长度不同
if(arrayA.length != arrayB.length) {
return false;
}
// 创建拷贝,不影响原数组
var arrayACopy:Array = arrayA.concat( );
var arrayBCopy:Array = arrayB.concat( );
// 如果忽略排列顺序
if(bNotOrdered) {
arrayACopy.sort( );
arrayBCopy.sort( );
}
// 循环比较
// 如果不匹配,删除拷贝,返回false
for(var i:int = 0; i < arrayACopy.length; i++) {
if(arrayACopy[i] != arrayBCopy[i]) {
delete arrayACopy;
delete arrayBCopy;
return false;
}
}
// 否则相等,删除数组,返回true
delete arrayACopy;
delete arrayBCopy;
return true;
}
ActionScript 3 Cookbook 中文版
第五章.数组
第 29 页 共 31 页
5.15. 创建联合数组
问题
我要创建用名称元素作为索引的数组
解决办法
创建联合数组
讨论
用联合数组其每个元素都有特定的含义,这一点原来的数组类型是做不到的。
var aMembers:Array = new Array("Franklin", "Gina", "Sindhu");
联合数组在其他的语言叫做哈希表,在 ActionScript 里它就是Object 类的一个实例,联合数组使
用名称元素来代替数字下标,该名称也被称为关键字或属性,说关键字更好理解些,它关联了元素
值,两者一一对应。
创建联合数组不是用Array 类而是Object类创建的,它就是 Object 类的一个实例,理论上 Object
类是任何类的基类。所有的对象都能作为联合数组,但是除非有特殊需要,最好还是用 Object 类
创建。
用{ } ,而且用逗号分开每个键值对,键值对之间用:,像下面:
var memebers:Object = {scribe: "Franklin",
chairperson: "Gina",
treasurer: "Sindhu"};
也可以像下面那样创建联合数组:
var members:Object = new Object( );
members.scribe = "Franklin";
members.chairperson = "Gina";
members.treasurer = "Sindhu";
有两种方法访问联合数组内容,一种是通过访问属性名称(关键字):
trace(members.scribe); // 显示: Franklin
另一种就像数组那样,把关键字作为下标来访问,用[ ] 符号:
trace(members["scribe"]); // 显示: Franklin
ActionScript 3 Cookbook 中文版
第五章.数组
第 30 页 共 31 页
这种方式更加灵活,可以在数组中进行遍历,对于动态生成的关键值和内容这种访问方式是最好的,
例如:
var members:Object = new Object();
members.councilperson1 = "Beatrice";
members.councilperson2 = "Danny";
members.councilperson3 = "Vladamir";
for (var i:int = 1; i <= 3; i++) {
trace(members["councilperson" + i];
}
数组访问方式在循环语句里经常用到:
var members:Object = new Object( );
members["councilperson"] = "Ruthie";
trace(members.councilperson); // 显示 Ruthie
members.councilperson = "Rebecca";
trace(members["councilperson"]); // 显示: Rebecca
ActionScript 3 Cookbook 中文版
第五章.数组
第 31 页 共 31 页
5.16. 读取联合数组
问题
我要怎样遍历联合数组
解决办法
使用 for . . . in 语句
讨论
基于整形下标的数组可以通过for 语句进行循环遍历,但是,用关键字作索引的联合数组就不能这
样遍历了,还好,联合数组可以通过 for . . . in 语句进行遍历访问。该语句会访问指定对象所有可
用的属性,语法如下:
for (key in object) {
// Actions
}
for . . . in 语句不需要循环变量更新语句,决定循环次数的是对象的属性个数。注意这key 就是存
储每个属性名称的:
var members:Object = new Object( );
members.scribe = "Franklin";
members.chairperson = "Gina";
members.treasurer = "Sindhu";
// 使用 for . . . in 语句遍历所有元素
for (var sRole:String in members) {
// 显示:
// treasurer: Sindhu
// chairperson: Gina
// scribe: Franklin
trace(sRole + ": " + members[sRole]);
}

Page:[«]1[»]

Categories

Lately left messages

Comments

Linkage

Misc