[转自
http://www.springparker.cn/blog/ 个人觉得这个教程写的不错,适合入门]
ActionScript 基础
第 1 部分: ActionScript 基础
从第 1 至 5 章将介绍有关 ActionScript 的基础知识. 这部分的内容主要是介绍性的, 并不要求你完全记住, 只要有个大概的印象就可以了(至少知道有这种东西存在, 在需要的时候能够找得到). 很多东西只有在实际的应用过程中才能完全理解和熟悉, 所以希望你能经常地尝试写一点东西(从修改范例开始是个不错的想法).
另外, 现在先不要抱怨我没有用什么特效范例来教 ActionScript, 因为还没到那一步. 那种狭隘的模仿是无法教给你真正的本事的, 不信, 你可以试试不读海明威的书就去模仿海明威的文风来写文章(譬如模仿《死在午后》).
创造力是建筑在认识的基础上的.
对于熟悉 C++ 或是 Java 的读者可以跳过这一部分. 当然, 如果要速成的话, 也可以跳过这一部分. 有时间, 还是看看好.
第 1 章: 代码格式及规范
1.1 代码格式
ActionScript 的每行语句都以分号 ";" 结束. 不同于 BASIC 语言, ActionScript 语句同 C++, Java, Pascal 一样允许分多行书写, 即允许将一条很的长语句分割成两个或更多代码行, 只要在结尾有个分号就行了. 允许语句分行书写的唯一缺点是(至少对许多熟悉 BASIC 的人而言): 语句末尾不能忘记加分号. 语句分行唯一的限制是字符串不能跨行, 即两个分号必须在同一行.
分行书写长语句也是一个很好的排版办法, 例如下面的语句段(目前你不需理解下面的语句是什么意思, 在双斜杠后面是注释):
duplicateMovieClip( "MyOldMovieClip", //旧的 MovieClip 实例名
"MyNewMovieClip", 999 ); //新复制的实例名和所在层次
setProperty( "MyNewMovieClipNameIsNewMC", //要修改其属性的 MovieClip 实例名
_alpha, "30"); //修改其透明度为 30%
但是在 Flash MX 中似乎自动格式化功能不是很完善. 上面的代码可以运行通过, 但在使用自动格式化时会出错. 问题就在于插入其间的注释语句. 毕竟上面我写的例子并不是很好地符合 Flash MX 的语法规范(但按照 C 语言的语法来看是绝对没问题的), 所以请记住: 只有在语句很长或是很复杂的情况下才使用多行书写.
--------------------------------------------------------------------------------
一个好的程序员会懂得在程序代码中加入注释. 但也许你会说: 没关系, 我知道我写的是什么. 但是假如你是在 1 个月后再读这段代码呢? 很明显, 你记不住. 所以多打几个字又有什么麻烦的?
给 ActionScript 代码加注释使用下面格式:
statements; //这是单行注释, 由双斜杠开头,这行的后面部份都是注释内容
statements; /* 这也是注释
只不过可以换行 */
就这么简单(却又十分有用). 注意 /* 和 */ 已经不建议使用了(因为必须配对, 所以经常会导致错误).
--------------------------------------------------------------------------------
除了注释, 增加代码可读性的另一途径是使用代码排版格式. 下面是一段具有高可读性的代码:
//计算 x 阶乘的函数
function f(x) {
if (x<=0) { //假如 x 小于等于 0
return 1; //返回 1
} else {
return x*f(x-1); //否则返回阶乘结果
}
}
Flash MX 之前版本必须由程序员自行编排代码格式, 而 Flash MX 的 Action 面板多了一个 Auto Format (自动格式化)按钮 , 可以用它来自动格式化代码(同时也会进行语法检查, 相当方便). 格式化的选项可以在 Action 面板弹出菜单的 Auto Format Options 项对应的对话框中设置. 下面是对 Actions 面板的一点介绍:
另外提一下, 代码的字体最好是"宋体", 9pt. 不过在中文系统下行号与代码似乎总是对不齐.
1.2 语法着色和代码提示
语法着色(Syntax Hightlighting)是许多编程语言的 IDE (集成开发环境)所具备的功能. Flash 也具有这项功能. 语法着色的颜色可以在 Action 面板弹出菜单的 Preferences... 项对应的对话框中设置.
对此, 没什么好详细解说的. 只是希望大家能利用语法着色来发现错误和阅读代码.
Flash MX 新增加的代码提示功能(Code Hints)对于熟悉 Visual Studio 6.0+ 版本的读者而言并不陌生. 例如在输入了一个对象名后再输入".", 就会显示相关的属性和方法列表; 在输入了函数名后输入"(", 就会显示相关的函数格式. 具体的可在输入代码时自己体会.
1.3 语法规范
1.3.1 关键字
关键字是任何一种语言程序的基本构造单位. 它是程序语言的保留字(Reserved Words), 不能被作为其它用途(不能作为自定义的变量, 函数, 对象名).
Flash 的 ActionScript 中关键字不是很多, 下面的它们的列表:
Flash MX ActionScript 的关键字
break 跳出循环体 instanceof 返回对象所属的类(Class)
case 定义一个 switch 语句的条件选择语句块 new 使用构造函数(Constructor)创建一个新的对象
continue 跳到循环体的下一项目 return 在函数中返回值
default 定义 switch 语句的默认语句块 switch 定义一个多条件选择语句块
delete 清除指定对象占用的内存资源 this 引用当前代码所在的对象
else 定义 if 语句返回为假时的语句块 typeof 返回对象的类型
for 定义一个循环 var 声明一个本地变量(Local Variable)
function 定义一个函数语句块 void 声明返回值类型不确定
if 定义一个条件语句块 while 定义一个条件循环语句块
in 在一个对象或元素数组中创建循环 with 定义一个对指定对象进行操作的语句块
列出这些并不是要求你像背单词一样把它们背下来(这也是为什么中国的教育质量这么差的原因), 只是希望大家记住: 在 Flash 中有一些作为关键字的单词是不能随意使用的. 这在分析错误的时候是很有用的(特别对于初学者).
1.3.2 大小写敏感
同 C++ 和 Java 一样, ActionScript 是区分大小写的.
这就意味着: If 并不等于 if. 假如在代码中使用了 If, 在运行和检查时都会产生错误. 避免这种情况发生其实很简单: 多注意一下输入的代码是否自动地被语法着色了(Syntax Hightlighting).
但是对于变量(Variable), 实例名(Instance Name)和帧标签(Frame Label), ActionScript 是不区分大小写的. 尽管如此, 我还是建议大家在书写代码时保持大小写一致. 这是个很好的习惯.
1.3.3 运算符
除了关键字, 程序语言中最重要的组成部分就是运算符. 先不要说我死板, 因为不了解这些东西, 你什么也做不成.
下面是运算符的列表, 运算符的优先级(即几个运算符出现在同一表达式中时先运算哪一个)从上到下递减:
运算符
描述
+ 一元(Unary)加
- 一元(Unary)减
~ 按位(Bitwise)逻辑非
! 逻辑非(NOT)
not 逻辑非 (Flash 4 格式)
++ 后期(Post)递加
-- 后期(Post)递减
( ) 函数调用
[ ] 数组(Array)元素
. 结构(Structure)成员
++ 先期(Pre)递加
-- 先期(Pre)递减
new 创建对象
delete 删除对象
typeof 获得对象类型
void 返回未定义值
* 乘
/ 除
% 求模(除法的余数)
+ 加
add 字符串(String)连接 (过去的&)
- 减
<< 按位左移
>> 按位右移
>>> 按位右移 (无符号 unsigned, 以 0 填充)
< 小于
<= 小于或等于
> 大于
>= 大于或等于
lt 小于 (字符串使用)
le 小于或等于 (字符串使用)
gt 大于 (字符串使用)
ge 大于或等于 (字符串使用)
== 等于
!= 不等于
eq 等于(字符串使用)
ne 不等于 (字符串使用)
& 按位(Bitwise)逻辑和(AND)
^ 按位逻辑异或(XOR)
| 按位逻辑或(OR)
&& 逻辑和(AND)
and 逻辑和 AND (Flash 4)
|| 逻辑或 OR
or 逻辑或 OR (Flash 4)
?: 条件
= 赋值
*= /= %=
+= -= &=
|= ^= <<=
>>= >>>=
复合赋值运算
, 多重运算
写了这么一大版(也可以说是抄了), 有什么用? 你会发现这些运算符与 C++ 和 Java 的运算符没什么很大的区别, 无论是形式上还是功能上. 作为初学者你必须记住其中比较常用的部分(不常用部分的说明文字背景较暗). 这对你今后写表达式有很大帮助.
--------------------------------------------------------------------------------
对于运算符的使用, 也有一些要注意的地方.
例如 and 和 or, 虽然对于效率而言与 && 和 || 没什么至关重要的区别, 但如果你过去使用过 BASIC, 你肯定会选择前者的表示方式; 假如你过去是使用 C++ 或是 Java 的, 那么你就会倾向于使用后一种方法. 就我个人的观点, 为了使代码具有高可读性, 初学者还是应该使用意思明了的 and 和 or.
特别是像 ?: 这类极其简化的运算符, 初学者更难以阅读. 例如下面代码:
x = 5;
y = 10;
z = (x < 6) ? x: y; //如果 x 小于 6, 就把 x 的值赋给 z, 否则将 y 的值赋给 z
trace (z); //返回 5
从上例开始, 本教程中的所有范例代码都可以复制粘贴到新建的 Flash 动画的第一帧的 Action 里. 然后通过 Control 菜单的 Test Movie 项或是按下组合键 CTRL+ENTER 运行它. 这样你就可以看看这些代码有什么实际效果了. 当然你也可以试着改动这些代码, 通过改动的效果来理解教程的内容.
就不如下面的代码易于理解(尽管很冗繁):
x = 5;
y = 10;
if(x < 6){ //如果 x 小于 6, 就把 x 的值赋给 z, 否则将 y 的值赋给 z
z = x;
} else {
z = y;
}
trace (z); //返回 5
1.3.4 常量
常量是在程序运行中不会改变的量.
例如数值 1,2,3..., 逻辑值 true, false 等等. 另外还有一些系统内建的常量, 具体的可以看帮助文件的内容.
1.3.5 表达式
在 ActionScript 中最常见的语句就是表达式, 它通常由变量名, 运算符及常量组成. 下面是一个简单的表达式:
x = 0;
左边是变量名(x), 中间是运算符(赋值运算符 "="), 右边是常量(数值 0). 这就是一个非常简单的赋值表达式. 由这个表达式我们可以声明(Declare)一个变量, 为下一步操作做准备.
表达式又分为赋值表达式, 算术表达式和逻辑表达式.
赋值表达式上面已经说明了, 就是给变量一个值. 算术表达式顾名思义就是做数学运算的表达式, 例如: 1+3 (返回值为数值 4). 逻辑表达式就是做逻辑运算的表达式, 例如: 1>3. 只不过逻辑表达式返回的是逻辑值而已. 前面的 1>3 返回值为 false, 即 1 大于 3 为假.
将多个表达式组合在一起就可以组成复合表达式, 一般我们用到的也是这种表达式. 例如:
t = 3*3+(2+3);
x = 1>3;
上面的第二行是一个逻辑-赋值复合表达式. 首先 Flash 计算逻辑表达式 1>3 的值(false), 然后将该值赋给 x (即 x = false;). 对于复合表达式的运算顺序可以参考上面的运算符表. 要改变运算顺序可以使用圆括号(例子的第一行), 这是同其它语言一致的.
第 2 章: 变量及数据类型
2.1 变量
2.1.1 定义变量
变量是什么? 大概说来就是存放信息的容器(更确切的说是指向内存空间中某个存贮位置的指针, 不过能够理解就行了, 何必去记这么抽象的定义). 只要能够理解它可以存放信息并可以通过各种途径改变其中的信息就可以了, 我又不是大学里面的老师, 整天就知道叫学生死记硬背定义, 实际的东西一点都没有, "一切为了考试".
还有一个概念: 什么叫初始化变量? 就是在定义时给它一个有效值以说明它的内容和数据类型. 就像下面的例子, 定义了一个字符串(String)变量:
MyString = "我不懂什么是初始化变量";
就这么简单, 但是也有要注意的问题:
变量名必须为有效的标识符(例如不能以数字和不允许使用的字符开头).
变量名不能与 ActionScript 关键字和常量相似或相同.
变量名在它的作用域(Scope)中必须是唯一的(在下面我们会提到什么是作用域).
--------------------------------------------------------------------------------
在这里顺道说一下习惯命名法, 目前以 C++ 的标准为基础, 结合 ActionScript 的特点加以变化:
变量的数据类型 习惯前缀 范例
字符串(String) sz 或是 str szAddress, szName, strComment
数值(Number) n 或是 i nCount, nSerialNumber
逻辑值(Boolean) b bVisible, bFlag, bEnabled
Array 对象 根据数组的数据类型命名 -
Button 对象 btn btnPlay, btnPost
MovieClip 对象 mc mcBall, mcMotion
TextField 对象 txt txtEntry, txtPassword
Sound 对象 snd sndBackground, sndClick
为什么要用这些固定的前缀? 为了方便代码的阅读和交流, 同时可以避免多数不经意的命名错误. 所以, 在写代码时请尽量按照这个命名法去做. (在本书中因为前面部分的范例代码较简单, 所以并没有使用这种命名法.)
2.1.2 变量作用域
也就是变量在什么范围内是可以访问的. 就好像在 C&C: Renegade 中的任务一样, 没有 Security Level 3 的 ID Card 就进不了安全级别为 3 的区域的.
作用域一般说来有三种: 时间线(Timeline), 局部(Local), 全局(Global).
--------------------------------------------------------------------------------
对于时间线范围的变量, 就像上面的例子一样用 = 赋值并声明, 当然你也可以用 set 动作(Flash 4, 不推荐使用的方法, 除非你觉得代码不够长):
set( MyString, "我不懂什么是初始化变量" );
时间线范围变量声明后, 在声明它的整个层级(Level)的时间线内它是可访问的.
--------------------------------------------------------------------------------
什么是局部变量? 我也常常问自己. 局部变量就是在声明它的语句块内(例如一个函数体)是可访问的变量, 通常是为避免冲突和节省内存占用而使用.
声明它可以使用 var 关键字:
function LocalVar(){
var MyLocalString = "这是一个局部字符串变量";
trace( "Inside: " + MyLocalString );
}
LocalVar();
trace( "Outside: " + MyLocalString );
上面的 MyLocalString 字符串变量在函数尾就会被自动清除出内存. 所以在外面的 trace 语句返回结果为空("Outside:"), 而函数体内的 trace 返回:"Inside: 这是一个局部字符串变量".
假如你删除了 var 关键字, 那么 MyLocalString 就成时间线范围的变量了. 运行后显示 Inside 和 Outside 都为 "这是一个局部字符串变量". 在后面的函数一章我们还会提到局部变量的内容.
也许你注意到了函数中有一个 trace 动作. 它可以在测试模式(Testing Movie, CTRL+ENTER 组合键)下把指定变量的值发送到输出窗口(Output Window), 以便在运行时检查处理变量的代码是否正常. 这是一个非常方便的检查方法, 在测试代码时经常使用.
在代码中如果遇到有不清楚的函数和关键字, 可以通过 Action 面板的参考按钮(Reference)打开参考面板显示光标所在位置关键字或内建函数以及对象的详细信息, 也可以通过组合键 SHIFT+F1 打开它. 下面是参考面板:
--------------------------------------------------------------------------------
全局变量, 顾名思义就是在整个 Movie 中都可以访问的变量. 它的声明比较特殊:
_global.MyGlobalString = "这是一个全局字符串变量";
声明使用了一个 _global 标识符和点语法(Dot Syntax, 将在后面的章节讨论). _global 标识符是在 Flash 6 中新增加的, 用于创建全局变量, 函数, 对象和类(Class, 不清楚类是什么的话可以看看 C++ 的书).
总的来说 _global 是一个与最底层 _level0 并列的对象. 所有的全局变量, 函数, 对象其实就相当于是它的属性, 方法, 子对象. 关于它的具体内容可以查阅帮助文件, 一般我们只要懂得用就行了.
全局变量会被同名的时间线变量和局部变量屏蔽(Obscured), 这时我们就要通过别的方式来访问它了. 看看下面的例子:
//定义全局变量
_global.x = "Global";
//一个简单的函数
function show() {
trace("没有局部变量时函数内: "+x);
var x = "Local";
trace("有局部变量时函数内: "+x);
trace("有局部变量时调用时间线变量: "+this.x);
}
//测试
trace("------没有时间线范围变量时------");
show();
trace("直接调用: "+x);
//设置时间线变量
x = "Timeline";
//测试
trace("-------有时间线范围变量时-------");
show();
trace("直接调用: "+x);
trace("有时间线范围变量时调用全局变量: "+_global.x);
由上例的结果可以看出, 在当前时间线范围内有和全局变量同名的变量时, 直接通过变量名只能访问时间线范围内的同名变量, 这时应该用 _global.变量名 来调用全局变量. 同样局部变量也会屏蔽时间线变量(这时可以用 this.变量名 来调用时间线变量)和全局变量(这时可以用 _global.变量名 来调用全局变量).
2.1.3 在代码中使用变量
使用变量很简单, 有点编程基础的读者都可以办到. 下面用一个例子来说明在 ActionScript 中变量的使用:
function vars(x){
if(x<5){ //如果 x 小于 5
x = x + 1; //x 加 1
} else {
x = 10; //否则赋值 10
}
trace("x="+x);
return x;
}
vars(2);
vars(6);
trace("x="+x); //测试 x 是否为局部变量
函数声明中的参数无需加 var 声明也自动作为局部变量(例如上面例子中的 x). 通过上面例子的最后一句就可以看出来(返回值为空).
我们可以看到, 上面定义的函数中对局部变量 x (在函数参数中声明)进行了 4 种操作:
赋值: 就是改变变量所存贮的内容.
运算: 使用运算符运算并返回结果. 上例中的 x = x + 1 可视为一个运算操作(x + 1)和一个赋值操作(x = ...)的复合语句. 对于逻辑运算(上面 if 语句的条件), 返回的为逻辑值 true 或 false(就像 x<5 在 x 为 4 时会返回 true).
函数及命令调用: 就如上面 trace("x="+x); 中的一样, x 是被作为参数传递给函数的, 它代表的是它所存贮的实际内容(在 return x; 中也一样).
在 ActionScript 中变量的使用具有很大的灵活性, 下面我们将会针对不同的数据类型进行讲解.
2.2 常见数据类型
2.2.1 字符串 | String
一个字符串就是一系列的字符, 例如 "This" 就是一个字符串.
定义一个字符串变量很简单, 只要在初始化时将一个字符串数据赋给它就行了:
chapter = "第 2 章";
section = "第 2 节";
section_name = "常见数据类型";
full_name = section + " " add section_name + 999; //连接字符串
if(typeof(full_name) ne "string"){
full_name = "类型错误!";
}
trace("full_name=" + full_name);
上面的第 4 行的 full_name 的值是前面两个变量(section 和 section_name)和一个常量(999)的运算结果(使用了 + 和 add 运算符, 它们的功能是相同的). 请注意, 这行代码最后面的数值常量 999 不是同一类型的数据, 如果在 Pascal 这种数据类型检查极其严格的语言中这行代码是错误的. 但是 ActionScript 可以自动将它转换为字符串格式, 而不需要专门的函数(当然, 最安全的方法是使用 Number 对象的 toString() 函数或是 String() 函数). 由此可见, ActionScript 是一种弱类型检查的语言(即不严格限制各种数据类型间的运算和传递), 这和 VB 倒是有点相似, 只不过更过分一点.
在后面我用了一个 if 语句来测试后面加上 999 的代码是否运行正常(即检查表达式返回的值是否为字符串, 尽管在实际中并没有这个必要). 注意我用的是字符串类型专用的逻辑运算符 ne, 当然这只是为了表现字符串数据类型的特殊性, 实际应用中用 != 也就可以了. 对于 typeof 操作符, 我们会在这一章的末尾详细讲解.
--------------------------------------------------------------------------------
在实际应用中, 有一些特殊的字符不能直接输入在字符串中, 例如不能在字符串中直接输入引号(会破坏字符串的完整性). 这时我们就需要用到转义字符了(Escaping). 要使用转义字符, 首先要输入一个反斜杠(\), 然后输入相应的代码. 详细的代码列表如下:
转义字符 代表字符
\b 退格字符 (ASCII 8)
\f 换页符 (ASCII 12)
\n 换行符 (ASCII 10)
\r 回车符 (ASCII 13)
\t 制表符 (ASCII 9)
\" 双引号字符
\' 单引号字符
\\ 反斜杠字符
\000 - \377 八进制表示的字符
\x00 - \xFF 十六进制表示的字符
\u0000 - \uFFFF 十六进制表示的 16 位 Unicode 字符
例如:
trace("He said:\"I don\'t care about you.\"\nAnd she smiled:\"Really?\"");
你可以根据上面的对照列表读出上面代码的字符串内的实际内容. 运行后的输出为:
He said:"I don't care about you."
And she smiled:"Really?"
可以看到, 转义字符都被转换为相应的实际字符了. 这就是转义字符的作用, 学过 C++ 的读者应该很熟悉了.
2.2.2 数值 | Number
ActionScript 中的数值型数据为双精度浮点数(不懂是什么意思也没关系, 反正知道是数值就行了, 那只不过是个范围限制).
对数值型数据可以进行任何相应操作. 如下例:
a = 1;
b = 2;
sum = a + b; //求 a, b 之和
if(sum>0){ //假如结果大于 0
square_root = Math.sqrt(sum); //使用 Math 对象的平方根函数求 sum 的平方根
}
trace("sum=" + sum);
trace("square_root=" + square_root);
完.
2.2.3 逻辑变量 | Boolean
逻辑变量又被称为布尔变量(由其英文名称而来). 它只有两个值: true 和 false. 在必要的情况下, ActionScript 会自动将它的值转换为 1 和 0, 你也可以用 1 和 0 给它赋值(这是可能是为了和 Windows API 函数调用兼容而产生的).
a = 10;
b1 = 1;
b2 = false;
if(b1 == true){
a = a + b1;
} else {
b2 = !b2;
}
trace("a=" + a);
trace("b1=" + b1);
trace("b2=" + b2);
上面代码混合了数值型和逻辑型变量的运算. a = a + b1 将逻辑值 b1(true 即 1)加到 a 上, b2 = !b2 则是对 b2 取反(即由 false 变为 true 或是由 true 变为 false, 因为逻辑值只有两种情况: 真或假). 你可以试着修改一下 b1 的值来看看不同的效果.
2.2.4 对象 | Object
对象是 ActionScript 中的一个重要数据类型. 说得更清楚一些, 它就是现在大多数编程语言中的类(Class).
其实在 Flash 中使用的 MovieClip 其实也属于一种预定义的类, 只不过它有些特殊而已.
关于对象我们会在后面章节详细介绍.
2.2.5 影片 | Movieclip
影片是 Flash 中唯一用来引用图像元素的数据类型. 你可以通过 MovieClip 对象的各种属性(Property)和方法(Method)来操作它的实例(Instance).
关于影片我们也会在后面详细讲解.
2.2.6 空 | Null
空? 我是说"空", 也就是什么都没有. 这种数据类型就是这个意思, 而且它只有一个值: null. 那么它有什么用呢?
用来表示一个变量尚未赋值
用来表示一个变量已经不包含数据
用来表示一个函数没有返回值
用来表示一个函数的某个参数被省略了
不要认为它毫无意义, 在涉及到具体的程序问题时它是非常有用的.
2.2.7 未定义 | Undefined
未定义类型同 Null 差不多, 也只有一个值: undefined.
它被用来表示一个变量尚未赋值.
2.3 typeof 操作符
在实际应用中我们经常遇到需要判断具体变量和对象的数据类型的情况. Flash 提供了一个很好用的 typeof 来解决这个问题. 特别是对于自定义函数的设计, 确定参数的类型是非常重要的步骤.
参数类型 返回值(字符串)
String string
MovieClip movieclip
Button object
TextField object
Number number
Boolean boolean
Object object
Function function
Undefined undefined
Null null
typeof 操作符的优先级很高, 可以在逻辑运算或是算术运算符之前被运算. 下面是它具体应用的例子:
//常数的类型
trace("数值常数 36 的类型: "+typeof 26);
trace("字符串常数 what 的类型: "+typeof "what");
//一般 typeof 操作符可以像 +, -, add 等操作符一样使用
//但为了避免出错还是建议你使用括号, 如下例
trace("逻辑常数 true 的类型: "+typeof(true));
//对象的类型
trace("对象 Object() 的类型: "+typeof (Object()));
trace("new String() 的类型: "+typeof new String()); //注意 new 操作符优先级比 typeof 高
//函数的方法的类型取决于其返回值
trace("Math.sqrt() 方法的类型: "+typeof Math.sqrt());
trace("Math.toString() 方法的类型: "+typeof Math.toString());
//null 空类型
trace("null 的类型: "+typeof null);
//在这里我用了多级 typeof 来看看 typeof 返回的值的类型
trace("typeof 返回值的类型: "+typeof (typeof null));
你还可以自己试着改动一下代码, 看看其它东西的 typeof 是什么.
第 3 章: 条件和循环
第 3 章: 条件和循环
3.1 综述
ActionScript 的条件和循环语句有 if, else, else if, for, while, do...while, for...in 和 switch. 在 Flash 中它们被叫做流程控制动作(Action), 但实际上, 其实质与其它程序语言没什么不一样的.
因为条件和循环语句是程序语言中最基础的, 也是最具有实用价值的语句, 所以要在这里仔细讲解一下. 对于有 C++ 和 Java 等编程经验的读者随意浏览一下就可以了.
3.2 条件语句
3.2.1 if
if 可以说是程序语言中最基本的条件判断语句. 无论在任何语言中都有它的身影.
由下面的例子可以了解它的格式:
name = "SiC";
//下面是 if 语句
if(name == "SiC"){
trace("作者");
}
if 语句通过判断其后圆括号内的逻辑表达式是否为 true 来确定是否执行大括号内的语句. 假如逻辑表达式 name == "SiC" 返回值为真, 就在输出窗口(Output Window)内显示"作者", 否则就不执行.
然后让我们设想一下下面例子的效果:
if(1){
trace("总是执行");
}
如果你还记得前面数据类型的内容, 那么应该可以看出, 这时的 if 语句基本上是多余的, 因为对于常量 1, 逻辑表达式的值恒为 true(其实 1 就是逻辑值 true 的数值表示形式). 但对于常量 0, 则永远为 false. 你可以试试把上例中的 1 改成一个字符串常量(例如 "hi!")看看会有什么效果.
再看一个例子:
name = "SiC";
//下面是 if 语句
if(name = "SiC"){
trace("作者");
}
比较一下看这个例子与第一个例子有什么不同? 不同之处就在于第一个用了 ==, 而这个用了 =. 对于这个例子, if 的判断永远为 true. 想想为什么? 问题就在于使用了赋值运算符 = 而不是逻辑运算符 ==. 对于赋值运算, 其返回的逻辑值总是 true. 这也是初学者常犯的错误.
一定要注意区分赋值运算符 = 和逻辑运算符 ==. 否则你会遇到一些莫名其妙的错误和问题, 而且语法检查也找不出错误(因为赋值运算表达式也是有效的条件表达式). 所以请记住, ActionScript 的相等逻辑运算符是 == 而不是 =.
3.2.2 if...else
假如想要在判断条件不成立时执行另一项操作时怎么办? 很简单, 在 if 语句后面加上个 else 语句块就可以了:
name = "未知";
//下面是 if...else 语句
if(name == "SiC"){
trace("作者");
} else {
trace("未知");
}
很简单吧? 只要把在判断结果为假时要执行的语句放在 else 后的大括号里就行了.
3.2.3 if...else if
如果要进行很多个条件判断怎么办? 也好办, 用 else if 解决:
name = "Sam";
//下面是 if...else if 语句
if(name == "SiC"){
trace("作者");
} else if(name == "Flash MX") {
trace("Flash MX 是软件名称.");
} else if(name != "未知") {
trace("谁是 " + name + "?");
} else {
trace("未知");
}
你可以接任意多个的 else if 来进行多个条件的判断, 最后的 else 语句块可有可无(根据实际需要选用). 唯一不足的就是 else if 太多时执行速度较慢(在其它程序语言中也是一大问题). 这时就轮到 switch 出场了.
3.2.4 switch
switch 在 Visual Basic 里面是个很好用的命令. 它可以通过判断不同的条件表达式来执行不同操作. 但是在 ActionScript 中就没有那么大的弹性了. 因为 ActionScript 中 switch 的条件被固定为 ===, 即绝对等于(包括数据类型也要相同), 不像在 VB 中可以额外使用 >, >= 之类的条件运算符. 所以, else if 在需要判断大于小于之类的情况下还是大有用处的. 现在来看看下面的例子:
mynumber = 3; //赋值给 mynumber
//下面是 switch 语句
switch (mynumber) {
case 1:
trace ("这是我希望得到的数字.");
break;
case 2:
trace ("这个数字比我的小一点.");
break;
case 3:
trace ("这是我的数字.");
break;
default:
trace ("这不是我要的数字.")
}
上面的例子是一个完整的 switch 语句块. 在 case 关键字后面的就是需要满足的条件, 如果都不满足, ActionScipt 会查找是否存在 default 语句块, 如果存在, 则执行其中的语句. 另外, 你可能已经发现在每个语句块后都有一个 break 关键字, 为什么呢? 因为如果没有用 break 来跳出 switch 条件选择语句, 程序会继续向下搜索满足条件的 case 项目(包括 defualt 块)并执行其中的语句. 下面是一个修改后的例子:
mynumber = 3; //赋值给 mynumber
//下面是没有加 break 的 switch 语句
switch (mynumber) {
case 1:
trace ("这是我希望得到的数字.");
case 2:
trace ("这个数字比我的小一点.");
case 3:
trace ("这是我的数字.");
default:
trace ("这不是我要的数字.")
}
运行一下这个例子, 你会发现会同时输出了 "这是我的数字" 和 "这不是我要的数字". 为什么? 因为没有了 break, 在运行了满足条件的 case 3: 语句块后, 条件选择语句仍会继续执行, 而 default 块作为默认条件, 它总是会被执行, 从而产生了这样的结果. 一些常见的程序错误也就由此而来.
在 ActionScript 中还有一个用于循环的 continue 命令, 它可以直接跳到所在循环的条件检测部分(即立即进行下一次循环的条件判断). 这个命令不常用到, 所以在这里没有讲解. 感兴趣的读者可以查阅 Flash 的 ActionScript Dictionary.
3.3 循环语句
3.3.1 for
对于 for 循环, 我想大多数读者都不会陌生. 下面是一个求 1 到 100 的自然数之和的程序段.
var sum = 0;
//下面是 for 循环
for (var i=1; i<=100; i++) {
sum = sum + i;
}
trace ("sum="+sum);
很显然, 这和 BASIC 的 for 语句有很大区别, 同 PASCAL 也有一定的差异. for 后面括号里面的内容分为三部分: 初始值; 循环条件; 循环值变化方式. 对于初始值没什么可说的, 随便取; 循环条件就是在什么条件下继续循环, 只要懂得逻辑表达式就可以了; 循环值的变化方式可以用任意的赋值语句来改变. 下面是一个修改后的例子:
var sum = 0;
//下面是 for 循环
for (var i=2; i<100; i+=2) {
sum = sum + i; //trace(i);
}
trace("sum="+sum);
上例中我把初始值 i 改为了 2, 条件改为 <100 (即不包括 100), 循环值变成每次加 2. 运行后看看结果, 结果是 1 到 100 的开区间中所有双数之和. 如果不清楚循环内部的工作机理, 可以删除上例中 for 循环体内 //trace(i); 前的双斜杠, 运行代码时会在输出窗口中列出每次的 i 值. 那么如果初值不满足循环条件会怎样? 你可以把 i=2 改为 i=100 看看.
对应于 for 还有一个 for...in 循环, 这涉及到数组和对象的内容, 在后面会介绍.
3.3.2 while & do...while
说实在话, 对于一般的编程 while 用得不多. 但是在需要的时候你才会发现它的价值.
while 循环在运行时遵循下面的步骤:
检查 while 后面括号内的条件是否成立.
如果条件成立, 运行语句块内的语句. 否则结束循环, 运行循环体后面的语句.
运行完语句块内的语句后回到第一步.
n = 0;
//下面是 while 循环
while(n < 5) {
n++;
}
trace("n="+n);
上面的例子运行结果为 n=5. 当 n 小于 5 时循环的条件成立, 于是运行其中的 n++ (即 n 增加 1). 当 n 等于 5 时, 因为循环条件已经不成立, 所以中止循环, 执行后面的 trace 语句.
--------------------------------------------------------------------------------
while 还有一个结构, 即 do...while 循环. 看看下面这个例子的输出, 你就可以理解 do...while 循环是如何工作的了.
n = 0;
//下面是 do...while 循环
do {
n++;
} while (n > 5)
trace("n="+n);
你会发现输出的结果是 n=1, 即使我们给的 n=0 并没有满足 n>5 这个条件, 循环体也执行了一次(n++). 这个例子说明了 do...while 循环是一个条件后测试语句, 即先执行一次代码然后再检测条件是否成立. 利用这个特点, 我们可以满足一些特殊的编程需要.
但是仅仅这些还不够, 我们还需要一些别的东西来满足重复的需要, 那就是函数.
第 4 章: 函数
第 4 章: 函数
4.1 函数的基本概念
终于写完了数据类型和条件以及循环语句部分, 现在可以讲讲函数了.
函数是在程序中可以重复使用的代码. 你可以将需要处理的值或对象通过参数的形式传递给函数, 然后由函数得到结果. 从另一个角度说, 函数存在目的就是为了简化编程的负担, 减小代码量和提高效率. 而一个写得好的函数, 就像一个"黑箱", 你只要懂得调用它就行了, 而不用去关心它的具体功能是如何实现的.
4.2 创建自己的函数
4.2.1 函数定义(Definition)
要创建一个函数, 就需要有函数的定义. 对于 ActionScript, 就没有什么返回值类型, 形参实参之类的东西好讨论了. 下面是一个简单函数的定义:
//计算矩形面积的函数
function areaOfBox(a, b) {
return a*b; //在这里返回结果
}
//测试函数
area = areaOfBox(3, 6);
trace("area="+area);
现在来分析一下函数定义的结构. function 关键字说明这是一个函数定义, 而不是一段执行代码. 其后便是函数的名称: areaOfBox. 函数名后面的括号内是函数的参数列表(也可以没有参数, 但括号是必须要有的). 紧接着的大括号内是函数的实现代码, 即 ActionScript 语句. 如果函数需要返回值, 可以使用 return 关键字加上要返回的变量名, 表达式或常量名. 在一个函数中可以有多个 return 语句, 但无论何时, 只要执行了其中的任何一个 return 后, 函数便自行终止而不会继续执行下去. 如果没有 return 语句, 则在函数尾最后一个语句执行后结束.
因为 ActionScript 的特殊性, 函数的参数定义并不要求参数类型的声明, 即可以不指定参数类型. 这省去了很多麻烦, 也带来了一些问题. 虽然把上例中倒数第二行改为 area = areaOfBox("3", 6); 也同样可以得到 18 的结果, 但是这对程序的稳定性非常不利(假如函数里面用到了 a+b 的话, 就会变成字符串的连接运算, 结果自然会出错). 所以, 有时候在函数中类型检查是不可少的.
在函数体中参变量用来代表要操作的对象. 你在函数中对参变量的操作, 就是对传递给函数的参数的操作. 上例中的 a*b 在你调用函数时会被转化为参数的实际值 3*6 处理.
--------------------------------------------------------------------------------
函数还有一种创建方法, 叫做函数显式声明(function literal, 不是通过正式的函数声明而是在一个表达式内通过未命名的函数来进行声明):
areaOfBox = function(a,b) {return a*b;};
trace("area="+areaOfBox(2,3));
这种形式的声明经常用在对象的方法或是函数库的函数声明中.
在 Flash MX 的帮助中函数定义部分关于这种声明的范例代码有误, 请注意.
--------------------------------------------------------------------------------
上面是有返回值的函数, 在函数尾使用了 return 关键字来返回结果. 函数也可以不返回任何值. 如下例:
//无返回值的函数
function areaOfBox(a, b) {
_root.area = a*b;
}
//测试函数
areaOfBox(3, 6);
trace("area="+_root.area);
它的结果也是 18, 只不过最后的结果是传递到 _root 下的指定变量 area 而已.下面一个例子更简单:
//计算矩形面积的函数
function simpleFunc() {
trace ("什么都没有"); //在这里返回结果
}
//测试函数
simpleFunc();
最后的输出就是 trace 中的字符串. 就是说, 函数可以既没有参数也没有返回值, 而是一系列操作的集合. 可见函数的使用具有很高的灵活性.
--------------------------------------------------------------------------------
同变量一样, 函数也可以具有全局性. 只要在声明时在前面给它加一个 _global 就可以了:
//计算矩形面积的全局函数
_global.areaOfBox = function (a, b) {
return a*b; //在这里返回结果
}
//测试函数
area = areaOfBox(3, 6);
trace("area="+area);
请注意: 在函数体中出现的关键字 this 代表的是调用函数的 MovieClip, 而不是函数体所在的 MovieClip. 这很容易被忽略而产生不期望的结果. 如果要指定 this 所代表的对象就要用到 Function.call() 和 Function.apply() 方法. 在后面的 arguments 对象介绍中会讲到.
4.2.2 函数参数的检查
为了保证函数运行的正确性, 我们有时必须检测用户是否给了足够的或是正确类型的参数. 下面是我对上面例子进行改动后的代码:
//计算矩形面积的全局函数
_global.areaOfBox = function (a, b) {
//输出两个参数之和, 用于理解下面的 typeof 语句
trace("a+b="+(a+b));
//检测参数是否足够且类型正确
if(a==undefined || b==undefined || typeof(a+b)!="number") {
trace("<参数错误>");
return 0; //返回 0 作为错误时的结果
}
return a*b; //在这里返回结果
}
//测试函数
trace("----下面是正确的参数----");
area = areaOfBox(3, 6);
trace("area="+area);
trace("----下面是错误的参数----");
//这里为了节省篇幅, 我在命令中直接调用函数, 而不是先将返回值赋给一个变量
//其实这才是我们常用的函数调用方法
trace("area="+ areaOfBox(3, "6"));
trace("----下面是不足的参数----");
trace("area="+areaOfBox(3));
上例中我用 a==undefined 来判断 a 是否被赋值了(即是否已定义, 对于 undefined 数据类型的内容请参阅前一章的内容). 为了确保万无一失, 我还用了 b==undefined 来保证 b 也已被赋值, 中间使用一个逻辑 "或" 运算符 || 来连接这两个条件.
此外, 在这两个条件后面我又通过 typeof(a+b)!="number" 来确认参数类型是否正确(关于 typeof 关键字的信息请参考前一章). 这里我利用了 ActionScript 的一个特点: 数值与字符串相加的和会被优先做为字符串处理. 所以 a+b 中只要有一个为字符串, 那么整个 a+b 的返回值就是一个字符串, 在后面通过 typeof 来检测的结果自然就不是我们所要的 "number". 通过 trace("a+b="+(a+b)); 输出的结果可以看出这一点.
--------------------------------------------------------------------------------
在 ActionScript 中除了用户定义的函数外, 还有预定义的内建函数. 对于不同的对象, 也有不同的函数(或者说是方法)可以调用. 下面是拥有最高优先级的系统内建函数列表:
函数 说明
Boolean 将所给参数值转化为逻辑值(也叫做布尔值)
escape 将所给参数转化为字符串并用 URL 格式编码(所有非标准字符将被转化为以 % 开头的十六进制值)
eval 返回所给参数表示的对象, 参数可以是常量, 表达式, 属性等(这在 DuplicateMovieClip 时经常用到)
getProperty 返回指定对象的指定属性值
getTimer 返回从动画开始运行到当前所经过的毫秒数
getVersion 返回 Flash 版本和操作系统信息
isFinite 返回所给参数是否是有穷的(逻辑型返回值)
isNaN 返回所给参数是否是数值(逻辑型返回值)
Number 将所给参数转化为数值
parseFloat 将字符串转化为浮点数, 如果不可转化则返回 NaN (Not a Number, 不是数值)
parseInt 将字符串转化为整数, 如果不可转化则返回 NaN (常用于数值进制转化, 浮点数转化后会转化为整数)
String 将所给参数转化为字符串
targetPath 返回字符串格式的指定对象的路径
unescape 返回用 URL 格式解码的字符串
上面的函数的详细信息请查阅 Flash 的 Action Dictionary. 要懂得如何通过最简捷的方法获取资料.
4.3 调用函数
4.3.1 直接调用
声明了函数, 就要用它. 怎么用? 像上面例子中我们用来测试的例子一样. 输入函数名和它需要的参数, 然后把返回值赋给一个变量. 但是, 最简单的方法莫过于直接调用函数而不赋值给变量, 函数的调用语句会被作为与返回值数据类型相同的常量处理. 也就是说, 有返回值的函数可以被当作一个该返回值数据类型的变量来使用. 例如, 在前一个例子中的 trace("area="+areaOfBox(3,"6")); 结果不变.
定义后的函数可以在其作用域内无限次地反复调用, 每次调用都可以给予不同的参数.
对于无参数的函数, 只要简单的输入它的函数名加括号 () 来调用就行了. 例如下面一个例子:
//获得 Flash 版本信息
trace( getVersion() );
上例我调用了一个系统内建的无参数函数, 它会返回当前的 Flash 版本. 对于自定义的无返回值函数, 也是像这样直接调用.
有时候即使没有给函数足够的参数, 函数的功能依然可以使用. 例如:
//检查参数是否是数值
trace( isNaN() );
在上例中我们并没有给函数一个必要的参数, 但函数仍然可以处理并返回 true (因为没有参数就等于给函数一个 Null 类型的常量, 因为 null 不是数值类型, 所以最后的返回值为 true).
对于前面几个范例中的 areaOfBox 函数, 你可以试试少给它一个参数, 看看会有什么结果.
4.3.2 通过 call 和 apply 方法调用
在 Flash 的 ActionScript 中函数(Function)其实是内建的对象. 所以我们可以通它的 call 和 apply 方法调用它:
//计算面积的函数
function areaOfBox(a, b) {
this.value = a*b; //将结果赋给 this 所代表的对象的 value 属性
}
//创建新对象
object_1 = new Object();
object_1.value = 0; //为对象加入 value 属性并给予初值 0
object_2 = object_1; //由 object_1 复制出一个 object_2, 此时两者的 value 属性均为 0
//测试函数
areaOfBox.call(object_1, 3, 6);
trace("object_1.value="+object_1.value);
array_ab = [4, 5]; //创建参数数组
areaOfBox.apply(object_2, array_ab);
trace("object_2.value="+object_2.value);
为什么要通过 call 和 apply 来调用函数? 这样不比前面的直接调用麻烦吗?
的确, 这样调用函数比较麻烦, 但你注意到了我使用的第一个参数没有? 通过第一个参数可以指定在函数体中的 this 关键字代表什么对象, 这就是用 call 和 apply 的好处(关于对象和 this 的内容在后面章节中才会提到, 在这里暂且不提). 这个好处只有在实际的编程中你才能体会得到, 这里只是简要介绍一下, 让你有个基本的概念.
如果函数中没有使用 this 关键字, 第一个参数要用 null 代替.
在本例中第一个返回值被放入 object_1 的 value 属性中, 另一个会被放入 object_2 的 value 属性中. 通过 call 和 apply 的第一个参数我们让函数体中的 this 先后代表了 object_1 和 object_2 两个对象. 第一个参数后面的实际参数的给予完全依照要调用函数的参数个数和类型确定.
至于 call 与 apply 的不同之处上面已经表示得很明白了: apply 的实际参数是通过数组传递的.
4.4 arguments 对象
arguments 对象, 顾名思义就是参数对象, 它包含的是函数调用的参数. 作为一个数组对象, 它只有三个属性:
属性 描述
arguments.callee 正被调用的函数
arguments.caller 正在进行此调用的函数
arguments.length 传递给被调用函数的参数数目
通过下面的范例和附图也许可以帮助你更清楚地了解 callee 和 caller 的关系:
//一个求平方和的函数
function sum1(x) {
//我们把 x>0 作为循环调用的条件
if (x>0) {
//通过 callee 来调用自身(因为自己是被调用的函数)
//同时将参数减 1(否则就成死循环了)
return x*x+arguments.callee(x-1);
} else {
return 0;
}
}
//另一个求立方和的函数
function sum2(x) {
if (x>0) {
//这里我们直接调用求平方函数
return sqr(x);
} else {
return 0;
}
}
//求平方函数(与 sum2 相互作用)
function sqr(x) {
if (x>0) {
//求平方, 然后通过 caller 反过来调用 sum2 函数(即调用求平方函数的函数)
return x*x+arguments.caller(x-1);
}
}
//通过测试来比较两者效果
trace("正确的参数---------------");
trace("sum(3)="+sum1(3)+" : "+sum2(3));
trace("sum(4.7)="+sum1(4.7)+" : "+sum2(4.7));
trace("sum(100)="+sum1(100)+" : "+sum2(100));
trace("错误的参数---------------");
trace("sum(-1)="+sum1(-1)+" : "+sum2(-1));
trace("sum(0)="+sum1(0)+" : "+sum2(0));
由上面的附图可以很明确地表现出 callee 和 caller 的不同. 一个是引用被调用的函数(callee), 另一个是引用正在调用函数的函数(caller). callee 常用于函数的递归(即循环调用自身). 通过 callee 调用自身可以避免因为改动声明部分的函数名, 但忘了改动函数体内的函数名而产生的错误. caller 常用在多个函数间的调用, 同时也可以用来判断调用者是谁(这样可以限定调用者范围和其它函数是否可以调用此函数).
至于 arguments.length 没什么可说的, 就是返回当前调用所传递的参数个数.
4.5 函数的其它特性
4.5.1 局部变量
在函数中使用的参数都是局部变量, 在函数调用结束后它们会被自动从内存中移除. 你也可以在函数中使用 var 声明其它的局部变量. 如果你在函数中使用了全局或是其它位置的变量, 一定要注意是否和函数中的局部变量混淆, 同时最好用注释标明它们不是函数的局部变量和它们的来源.
function test(a) {
var b = "Words"; //定义局部变量 b
c = "Text Here"; //定义变量 c
trace("----从内部访问变量----");
trace("a="+a); //显示参数 a
trace("b="+b); //显示局部变量 b
trace("c="+c); //显示变量 c
}
//调用函数
test("Symbol");
trace("----从外部访问变量----");
trace("a="+a);
trace("b="+b);
trace("c="+c);
由运行结果可以看出来参数 a 和局部变量 b 都只在函数体内可以访问, 而在函数内部定义的变量 c 则可以在函数体外部访问.
4.5.2 作用域
函数的作用域是定义它的代码所在的对象或时间线范围. 全局函数其实相当于一个基于 _global 全局对象的子函数.
如果要调用其它位置(即不在同一对象层内的函数), 必须使用路径(Path). 如在一个子 MovieClip 中要调用 _root 中的函数必须要用以下格式:
_root.myFunction();
若是要调用父级 MovieClip 下面的 mc1 里面的 mc2 里面的函数 myFunction 则要用以下代码:
_parent.mc1.mc2.myFunction();
说得更明确一点, 就是你在一个对象或是层级中定义了一个函数, 就等于为这个对象(或者说是类, Class)或层级增加了一个子函数(或是方法, Method). 要调用这个函数, 你就必须指明它所属的对象或是层级. 这也使得在不同的对象中可以用相同的函数名来创建函数(变量和对象也是一样). 关于路径的内容将后面的章节提到.
4.5.3 函数的重定义
在 ActionScript 中, 当你重新定义了一个函数后, 这个函数就会被改写为新的版本, 旧的函数被覆盖. 你再次调用它时, 它就是新的函数了. 至于函数重载(C++ 的特色)这种东西在 ActionScript 中是没有的, 所以也不用费力气讲了.
关于函数的内容就简要介绍到这里. 在下一章我们会讨论在实际应用中非常有用的数组.
第 5 章: 数组
第 5 章: 数组
5.1 什么是数组?
终于写完了数据类型, 条件循环语句以及函数部分, 现在可以讲讲数组了.
那么, 什么是数组呢? 我也不懂该怎么定义. 所以就从 C++ 的教材上抄了一段: 数组由许多相同类型的数据项和索引变量组成, 数组不是一种基本数据类型, 它是由数据类型组成的集合类型.
算了, 这么多字, 人都会被绕糊涂, 还是来个大概吧: 数组就是许多对象的集合, 对象的类型可以为数值, 字符串, 其它对象等等. 你可以通过每个元素的序号(叫做索引, index)来访问指定的元素. 它的功能同变量一样, 也是存贮数据的地方, 只不过是一个"集中营"而已.
ActionScript 中的数组其实是系统内建的对象类型, 之所以要将它的对象性提前到这里讲, 是因为它的用途非常广泛(也因为在 C++ 的教材里面它被放在基础部分). 譬如说, 你可以用它来存贮一个名单或是一系列坐标等.
5.2 创建数组
到现在为止还没有让大家看看数组长什么样, 是不是值得花那么多时间学, 那么, 就让我们看看它的真面目吧:
team_member = new Array();
team_member[0] = "SiC";
team_member[1] = "ReDo";
team_member[2] = "Crab_D";
trace(team_member); //显示数组内容
上面就是数组 team_member 的定义语句, 它定义了一个包含 3 个字符串的数组(即数组长度为 3). 给它赋值的语句中, 在team_member 后面的方括号里是每个元素的索引(索引由 0 开始). 其实例子中是通过 new 关键字创建一个 Array 对象的实例, 这些我们会在有关对象的章节中提到, 这里请你先记住它.
同 C 和 Java 一样, ActionScript 中的数组索引也是由 0 开始的. 在编程时应特别注意, 因为这也是初学者的常见错误之一.
如果你觉得上面的语句太繁琐, 那么上面的例子可以改为如下形式:
team_member = new Array("SiC", "ReDo", "Crab_D");
trace(team_member); //显示数组内容
它的作用与上例相同, 只不过更简洁一点. 如果要更简捷, 就用下面的方法:
team_member = ["SiC", "ReDo", "Crab_D"];
trace(team_member); //显示数组内容
注意, 这里代码中用的是方括号. 今后使用数组时可以根据具体情况选用不同的方法, 不过用得最多的还是这种.
至于用 new Array(数组长度) 创建指定长度的空数组, 因为实用价值不高(虽然在读取外部数据时可能会用到), 而且也很容易理解, 所以就不讨论了, 其方法是一样的.
--------------------------------------------------------------------------------
有时候我们希望在一个元素中包含多个元素(即元素又是一个数组), 这时候就要用到多维数组了.
对于多维数组, 最简单的创建方法就是使用方括号:
//不要忘了下面的 var 代表着什么, 如果真的忘了就看看数据类型那一章
var team_member = [[ "SiC", "无业游民", 1011 ],
[ "ReDo", "游戏杀手", 2172 ],
[ "Crab_D", "帮倒忙", 1012 ]];
trace(team_member.join("\n")); //显示数组内容
每个元素(即子数组)在 trace 输出时用 \n (换行符)分隔开. 另外在每个子数组中的元素数目也可以不相同, 这里就不举例了.
5.3 访问数组
其实访问数组的方法很简单, 第一个例子的赋值语句就已经表明了这一点. 要修改数组中某个元素的值, 只需要用 数组名[索引号] = 新值; 的格式赋值. 如果要像变量一样引用某一个元素, 只需要用 数组名[索引号] 来表示该元素就行了. 对于多维数组, 格式为 数组名[索引号1][索引号2][索引号3]...(有多少个方括号就看你要访问的是那一级的数组元素了). 下面是一个简单的例子:
var team_member = [[ "SiC", "无业游民", 1011 ],
[ "ReDo", "游戏杀手", 2172 ],
[ "Crab_D", "帮倒忙", 1012 ]];
team_member[1] = [ "UnDo", "游戏白痴", 2171]; //修改第 2 个元素(子数组)
team_member[2][1] = "关心"; //修改 "帮倒忙" 为 "关心"
trace(team_member.join("\n")); //显示数组内容
--------------------------------------------------------------------------------
有一点方便普通用户的功能是: ActionScript 的数组对象是动态的, 没有 C 语言中静态数组和动态数组的分别(毕竟不会复杂到让用户分配内存的地步). 也就是说, 你可以很方便的任意添加或移除数组元素:
team_member = new Array("SiC", "ReDo", "Crab_D"); //原来只有 3 个元素
team_member[3] = "You"; //添加第 4 个元素, 注意索引为 4-1=3
trace(team_member); //显示数组内容
上例为数组添加了第 4 个元素 "You" (请注意不是第 3 个, 索引号是从 0 开始的). 从 trace 的结果可以看出这一点.
--------------------------------------------------------------------------------
对于多维数组, 只能通过父级元素添加新元素(注意新添加的元素可以有不同数目的子元素):
var team_member = [[ "SiC", "无业游民", 1011 ],
[ "ReDo", "游戏杀手", 2172 ],
[ "Crab_D", "帮倒忙", 1012 ]];
team_member[3] = ["You", "Unknown"]; //添加新元素
team_member[0][3] = ["Yeah!"]; //添加一个新的子数组到已有元素(子数组)
team_member[0][3][1] = "Hmm?"; //添加一个新元素到新的子数组中
trace(team_member.join("\n"));
上面的例子不能用 trace 的结果表现出 "Yeah!" 和 "Hmm?" 构成的子数组(它们被紧接着父数组显示出来了, 而且也是用逗号分隔). 你可以在 Debug Movie (调试动画, Ctrl+Shift+Enter) 中用 Debugger (调试)窗口的 Variables (变量)页面查看 _level0 中 team_member 数组的内容. 注意, 进入 Debug 模式后动画是暂停的, 数组还没有定义, 要按 F8 运行后才能查看其内容. 下面是对 Debugger 面板的一点介绍:
--------------------------------------------------------------------------------
ActionScript 中的数组有个很特殊的优点: 可以使用字段名. 这样的数组更像一个二维数据表(但实际上这是个对象的数组, 注意在定义每个子元素时使用的是大括号而不是中括号).
var team_member = new Array();
team_member[0] = {name: "SiC", job: "无业游民", sn: 1011};
team_member[1] = {name: "ReDo", job: "游戏杀手", sn: 2172};
team_member[2] = {name: "Crab_D", job: "帮倒忙", sn: 1012};
trace(team_member[1].name); //显示第 2 个元素中的 name 字段
后面的 trace 语句显示第二个元素的 name 字段的内容. 但实际上这是通过 team_member[1] 引用数组的第二个元素(一个对象), 然后通过点式语法引用其属性 name 的值. 你可以通过 Debugger 来查看这个数组的内容. 关于对象的具体内容将在后面章节中说明.
5.4 数组对象(Array)
在前面我们提到数组也是系统内建对象, 那么现在我们要讨论一下作为对象的数组有什么特殊性质.
作为一个对象, 自然会有一些属性(Property)和方法(Method)可供使用. 下面就是它们的列表:
属性 描述
Array.length 返回数组长度
方法 描述
Array.concat 连接指定数组和参数中的各个数组成为新的数组并返回.
Array.join 将数组中所有元素连接成为一个字符串.
Array.pop 移除数组的最后一个元素并返回它的值.
Array.push 在数组末尾添加一个元素并返回新的数组长度.
Array.reverse 反转数组元素. (相当方便, 特别是在写某些特效时)
Array.shift 移除数组的第一个元素并返回它的值.
Array.slice 将数组的指定部分以一个新的数组返回. (不影响原数组)
Array.sort 对数组排序. (免去了另写排序函数的必要)
Array.sortOn 按字段名对数组排序.
Array.splice 添加和/或移除数组元素.
Array.toString 返回以逗号 "," 分隔的数组元素列表字符串.
Array.unshift 在数组开头添加一个或多个元素并返回新的数组长度.
这里面最常用的是 length 属性. 在写循环时, 有时我们不能确定要处理数组的元素数目, 这时候就可以通过 length 属性获得其数目. 至于其它的那些方法, 在用到的时候查查帮助和参考里面的详细信息就够了.
//显示数组内容的函数
function show_member(comment) {
if (my_team != undefined) { //确认数组是否存在
trace(my_team.join(" , ") add " << " add comment); //在数组内容后面我加了个注释, 便于在输出时辨认
} else {
trace("数组未定义!");
}
}
//为数组元素添加序号的函数
function add_number(the_array) {
if (the_array != undefined && the_array.length>2) { //确认数组存在并且长度大于 2
for (i=0; i the_array[i] = i add ": " add the_array[i]; //这里的运算符看不懂就回头看看第一章
}
} else {
trace("数组不存在或只有一个元素!");
}
}
//测试函数工作是否正常
show_member();
add_number(my_team);
//创建数组
my_team = new Array();
my_team = ["SiC", "ReDo", "Crab_D"];
show_member("有 3 个元素");
//调用数组对象的 splice 方法, 删除 ReDo, 添加 UnDo 和 EdeN
//第一个参数为要删除的第一个元素的 index, 第二个参数为要删除的元素个数
//后面的参数是要在删除的位置添加的元素
my_team.splice(1, 1, "UnDo", "EdeN");
show_member("调用 splice 方法修改后的数组")
//调用函数处理数组
add_number(my_team);
show_member("添加了序号后的数组");
//反向数组
my_team.reverse();
show_member("反向后的数组");
//去掉第一个和最后一个元素
my_team.shift();
my_team.pop();
show_member("去掉头尾元素的数组");
//在开头添加元素
my_team.unshift("6: Doggie", "7: Zero");
show_member("在开头添加元素");
//在末尾添加元素
my_team.push("7: Who?", "0: Ghost");
show_member("在末尾添加元素");
//按升序排序, 要降序只需再调用一个 reverse 方法即可
my_team.sort();
show_member("排序后数组");
上面的这个例子就比我们以往的例子要长一些了. 首先看看最前面我们声明的两个函数.
第一个函数主要通过 trace 输出数组的内容., 我使用了一个 join 方法将数组元素用指定字符连接并以字符串形式返回. 为了保证不会因为传递给函数的数组参数名称错误或定义失败而产生错误, 我在输出前用了一个条件语句来判断参变量是否 undefined (未定义, 回想一下前面在数据类型介绍中提到的内容).
第二个函数主要是演示 length 属性的使用. 其中的 for 循环通过使用 length 属性判断是否到达数组尾. 由于 length 会随所给数组的不同而变化, 所以 for 循环可以处理任意长度的数组, 而不必担心出现下标越界问题(即调用数组元素时使用了过大或过小的索引值).
在后面紧接着的是测试函数工作是否正常的语句. 我故意在数组还未定义时就调用这两个函数, 结果返回了函数里我们预先设定的错误信息(如果函数没有判断参数是否已定义的部分, Flash 也会返回错误信息).
然后就是测试的主体部分. 这些部分特别需要解释的, 自己看注释就行了. 关于其中用到的 splice 方法可以查询 Flash 的 ActionScript Dictionary 或是 References 面板. 今后在别人的代码中发现不熟悉的东西时, 要懂得利用 Flash 本身附带的帮助文件.
然后, 关于数组的内容也就简单地介绍到这里了. ActionScript 的基础部分到此结束, 后面是面向对象编程的内容.
********************************************
請教beginGradientFill的matrix的用法
請教MovieClip.beginGradientFill的用法。
下面是中文版HELP的解釋:
MovieClip.beginGradientFill
可用性
Flash Player 6。
用法
myMovieClip.beginGradientFill (fillType, colors, alphas, ratios, matrix)
参数
fillType 字符串“linear”或字符串“radial”。
colors 一个数组,包括要在渐变中使用的 RGB 十六进制颜色值(例如,红色是 0xFF0000,蓝色是 0x0000FF,等等)。
alphas 一个数组,包括与 colors 数组中颜色相对应的 Alpha 值;有效值为 0 到 100。如果该值小于 0,则 Flash 使用 0。如果该值大于 100,则 Flash 使用 100。
ratios 颜色配额的数组;有效值为 0 到 255。该值按 100% 定义了对颜色进行采样处的宽度的百分比。
matrix 一个变形矩阵,是带有下列两组属性之一的一个对象:
a、b、c、d、e、f、g、h、i,它们用于描述下列形式的 3 x 3 矩阵:
a b c
d e f
g h i
下面的示例使用 beginGradientFill 方法,其 matrix 参数是具有这些属性的对象。
_root.createEmptyMovieClip( "grad", 1 );
with ( _root.grad )
{
colors = [ 0xFF0000, 0x0000FF ];
alphas = [ 100, 100 ];
ratios = [ 0, 0xFF ];
matrix = { a:200, b:0, c:0, d:0, e:200, f:0, g:200, h:200, i:1 } ;
beginGradientFill( "linear", colors, alphas, ratios, matrix );
moveto(100,100);
lineto(100,300);
lineto(300,300);
lineto(300,100);
lineto(100,100);
endFill();
}
如果 matrixType 属性不存在,则其余参数都是必需的;如果缺少其中任何一个则该函数会失败。该矩阵缩放、平移、旋转和倾斜在 (-1,-1) 和 (1,1) 处定义的单位渐变。
matrixType、x、y、w、h、r。
这些属性表示下列含义:matrixType 是字符串“box”、x 是相对于该渐变左上角父级剪辑的注册点的水平位置,y 是相对于该渐变左上角父级剪辑的注册点的垂直位置,w 是渐变的宽度,h 是渐变的高度,r 是渐变的旋转角度(以弧度为单位)。
下面的示例使用 beginGradientFill 方法,其 matrix 参数是具有这些属性的对象。
_root.createEmptyMovieClip( "grad", 1 );
with ( _root.grad )
{
colors = [ 0xFF0000, 0x0000FF ];
alphas = [ 100, 100 ];
ratios = [ 0, 0xFF ];
matrix = { matrixType:"box", x:100, y:100, w:200, h:200, r:(45/180)*Math.PI };
beginGradientFill( "linear", colors, alphas, ratios, matrix );
moveto(100,100);
lineto(100,300);
lineto(300,300);
lineto(300,100);
lineto(100,100);
endFill();
}
如果 matrixType 属性存在,则它必须等于“box”,并且其余参数都是必需的。如果这些条件中的任何一个不满足,则该函数将失败。
返回
无。
说明
方法;指示新的绘画路径的开始。如果第一个参数为 undefined,或者未传递任何参数,则该路径将不填充。如果存在一个开放路径(即如果当前的绘画位置不等于 moveTo 方法中指定的上一个位置),并且该路径具有与其关联的填充,则用线条闭合该路径,然后进行填充。这类似于调用 endFill 方法时的情形。
如果存在下列任意一种情况,则该方法将失败:
colors、alphas 和 ratios 参数中的项目数不相等。
fillType 参数不是“linear”或 “radial”。
表示 matrix 参数的对象中的任意一个字段缺少或无效。
示例
下列代码使用两种方法绘制两个堆积矩形,这两个矩形具有红蓝渐变填充并使用 5 磅纯绿色笔触。
_root.createEmptyMovieClip("goober",1);
with ( _root.goober )
{
colors = [ 0xFF0000, 0x0000FF ];
alphas = [ 100, 100 ];
ratios = [ 0, 0xFF ];
lineStyle( 5, 0x00ff00 );
matrix = { a:500,b:0,c:0,d:0,e:200,f:0,g:350,h:200,i:1};
beginGradientFill( "linear", colors, alphas, ratios, matrix );
moveto(100,100);
lineto(100,300);
lineto(600,300);
lineto(600,100);
lineto(100,100);
endFill();
matrix = { matrixType:"box", x:100, y:310, w:500, h:200, r:(0/180)*Math.PI };
beginGradientFill( "linear", colors, alphas, ratios, matrix );
moveto(100,310);
lineto(100,510);
lineto(600,510);
lineto(600,310);
lineto(100,310);
endFill();
}
matrix 一个变形矩阵,是带有下列两组属性之一的一个对象:
matrix我不明白。
转载于:https://www.cnblogs.com/savageworld/archive/2006/07/28/462434.html