[转载]走在网页游戏开发的路上(三)
0. 前言
函数:完成某个目标任务的代码块,它是代码重用的最小单位。
函数是可在ActionScript中调用的基本代码单位。ActionScript中用户定义的函数和内置函数都由Function对象来表示,该对象是Function类的实例。
类的方法与Function对象略有不同。与普通函数对象不同,方法和与其关联的类对象紧密关联。因此,方法或属性具有在同一类的所有实例中共享的定义。可以从实例提取方法并将其处理为“绑定”方法(保留与原始实例的链接)。对于绑定方法,this关键字指向实现该方法的原始对象。对于函数,this在调用函数时指向关联对象。
1. 函数定义
在ActionScript 3.0中可通过两种方法来定义函数:使用函数语句和使用函数表达式。可以根据自己的编程风格(偏于静态还是偏于动态)来选择相应的方法。如果倾向于采用静态或严格模式的编程,则应使用函数语句来定义函数。如果有特定的需求,需要用函数表达式来定义函数,则应这样做。函数表达式更多地用在动态编程或标准模式编程中。
1.1函数语句
函数语句是在严格模式下定义函数的首选方法。函数语句以 function 关键字开头,后跟:
l 函数名
l 用小括号括起来的逗号分隔参数列表
l 用大括号括起来的函数体——即,在调用函数时要执行的ActionScript代码
function 函数名(参数1:参数类型, 参数2:参数类型...):返回类型 { //函数体 } |
如: function add(a:int, b:int):int { return (a + b); } |
1.2函数表达式
声明函数的第二种方法就是结合使用赋值语句和函数表达式,函数表达式有时也称为函数字面值或匿名函数。这是一种较为繁杂的方法,在早期的ActionScript版本中广为使用。
带有函数表达式的赋值语句以var关键字开头,后跟:
l 函数名
l 冒号运算符 (:)
l 指示数据类型的 Function 类
l 赋值运算符 (=)
l function 关键字
l 用小括号括起来的逗号分隔参数列表
l 用大括号括起来的函数体——即,在调用函数时要执行的 ActionScript 代码
var 函数名:Function = function (参数1:参数类型, 参数2:参数类型...):返回类型 { //函数体 } |
如: var add:Function = function (a:int, b:int):int { return (a + b); } |
请注意,就像在函数语句中一样,在上面的代码中也没有指定函数名。函数表达式和函数语句的另一个重要区别是,函数表达式是表达式,而不是语句。这意味着函数表达式不能独立存在,而函数语句则可以。
2. 两种定义的区别/选择
这种两种定义方法在一般使用中不会感觉有什么不同。平时,应尽量时候用函数语句定义方法,这种方法更加标准、简洁。
在定义位置上,函数语句方法在编译时会被提升到最前面,而函数表达式方法只能先定义再使用,只有在定义后面的语句才可以成功调用。
函数语句定义法和函数表达式定义法还体现在函数体中this关键字的记忆上,使用函数语句定义法,则this关键字牢牢指向当前函数定义的域;而使用函数表达式定义法,则随着函数附着的对象不同,this关键字也随之改变。
函 数语句与表达式之间还有个细微的区别:体现在内存管理和垃圾回收方面。因为,函数表达式不像对象那样独立存在,它相当于一个匿名函数。当持有这个函数引用 的数组或对象脱离作用域或由于其他原因不再可用,那么将没有任何方法再访问该匿名函数。此时,这匿名函数对象引用计数为零,符合垃圾回收条件,这意味着可 能被回收。
3. 函数作用域、嵌套、闭包
要理解函数嵌套和闭包必须得先弄清作用域,下面分两小节来介绍。
3.1作用域
函数的作用域不但决定了可以在程序中的什么位置调用函数,而且还决定了函数可以访问哪些变量。适用于变量标识符的作用域规则同样也适用于函数标识符。在全局作用域中声明的函数在整个代码中都可用。例如,ActionScript 3.0 包含可在代码中的任意位置使用的全局函数,如 isNaN() 和 parseInt()。嵌套函数(即在另一个函数中声明的函数)可以在声明它的函数中的任意位置上使用。
无论何时开始执行函数,都会创建许多对象和属性。首先,会创建一个称为激活对象(active object)的特殊对象,该对象用于存储在函数体内声明的参数以及任何局部变量或函数。由于激活对象属于内部机制,因此无法直接访问它。接着,会创建一个范围链,其中包含由 Flash Player 或 Adobe AIR 检查标识符声明的对象的有序列表。所执行的每个函数都有一个存储在内部属性中的作用域链。对于嵌套函数,范围链始于其自己的激活对象,后跟其父函数的激活对象。作用域链以这种方式延伸,直到到达全局对象。全局对象是在 ActionScript 程序开始时创建的,其中包含所有的全局变量和函数。
3.2函数嵌套、闭包
函数可以嵌套,这意味着函数可以在其它函数内部声明。除非将对嵌套函数的引用传递给外部代码,否则嵌套函数将仅在其父函数内可用。例如,下面的代码在getNameAndVersion()函数内部声明两个嵌套函数:
嵌套函数例子: |
function getNameAndVersion():String { function getVersion():String { return "9"; } function getProductName():String { return "Flash Player"; } return (getProductName() + " " + getVersion()); } trace(getNameAndVersion()); |
在将嵌套函数传递给外部代码时,它们将作为函数闭包传递,这意味着嵌套函数保留在定义该函数时处于作用域内的任何定义。关于闭包,最简单的描述就是:
l 允许使用内部函数--即函数嵌套。
l 而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。
l 当其中一个内部函数在包含它们的外部函数之外被调用时,就会形成闭包。也就是说,内部函数会在外部函数返回后被执行。
l 而当这个内部函数执行时,它仍然必需访问其外部函数的局部变量、参数以及其他内部函数。这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,但也会受到内部函数的影响。
说完了通俗的理解,下面看下比较官方的定义。闭包(closure)是词法闭包的简称,对闭包的定义有很多种说法,可以分为两类:
F 一种说法是闭包是符合一定条件的函数——闭包是在其词法上下文中引用了自由变量(free variables,指除局部变量意外的变量)的函数
F 另一种说法是闭包是由函数和与其相关的引用环境组合而成的实体——在深约束(binding,国内很多人都翻译为绑定)是,需要创建一个能显示表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。
我更赞同第二种说法。
(关于函数还有很多要说的,如在ActionScript3中函数可以使用表达式定义及也是对象,这样可以对函数使用一些技巧。但是我想尽快介绍一些ActionScript3实际的开发经验,不是这些语言语法东西)接下来的文章我将介绍:
-
ActionScript3的类、包等基础知识
-
ActionScript3的事件机制
-
ActionScript3的动画原理
-
ActionScript3获取外部数据(加载XML、JS通信)
-
ActionScript3开发一个转盘抽奖程序
-
ActionScript3实现游戏中的计时器
-
。。。
作者:吴秦
出处:http://www.cnblogs.com/skynet/
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名吴秦(包含链接).