代码改变世界

走在网页游戏开发的路上(三)

2011-06-04 17:22  吴秦  阅读(10870)  评论(1编辑  收藏

 

AS3之函数

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关键字也随之改变。

函数语句与表达式之间还有个细微的区别:体现在内存管理和垃圾回收方面。因为,函数表达式不像对象那样独立存在,它相当于一个匿名函数。当持有这个函数引用的数组或对象脱离作用域或由于其他原因不再可用,那么将没有任何方法再访问该匿名函数。此时,这匿名函数对象引用计数为零,符合垃圾回收条件,这意味着可能被回收。

要理解函数嵌套和闭包必须得先弄清作用域,下面分两小节来介绍。

函数的作用域不但决定了可以在程序中的什么位置调用函数,而且还决定了函数可以访问哪些变量。适用于变量标识符的作用域规则同样也适用于函数标识符。在全局作用域中声明的函数在整个代码中都可用。例如,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实现游戏中的计时器
  • 。。。