AS3 (2) 函数

1.函数方法和函数闭包

AS3 中存在两种函数:函数方法和函数闭包。如果将函数定义为类定义的一部分或者将它附加到对象的实例,则该函数称为方法。如果您以其它任何方式定义函数,则该函数称为函数闭包。

2.函数定义

AS3 中通过两种方法来定义函数:使用函数语句和使用函数表达式。函数表达式有时也称为函数字面值或匿名函数。例如,下面的代码使用函数表达式来声明 traceParameter 函数:

var traceParameter:Function = function (aParam:String)
{
    trace(aParam);
};
traceParameter("hello"); // hello

函数表达式不能独立存在,只能用作语句(通常是赋值语句)的一部分。下面的示例显示了一个赋予数组元素的函数表达式:

var traceArray:Array = new Array();
traceArray[0] = function (aParam:String)
{
    trace(aParam);
};
traceArray[0]("hello");

一般认为,函数表达式更适合于关注运行时行为或动态行为的编程。

3.函数调用

第一种:用点语法来调用

class Example
{
  var methodExpression = function() {}
  function methodStatement() {}
}
var myEx:Example = new Example();
myEx.methodExpression(); // error in strict mode; okay in standard mode
myEx.methodStatement(); // okay in strict and standard modes

第二种:可以使用中括号 ([]) 代替点运算符 (.) 来调用该方法。

myExample["methodLiteral"]();

第三种:将整个类声明为动态类,以使用点运算符来调用方法。但缺点是,该类的所有实例在严格模式下都将丢失一些功能。例如,如果您尝试访问动态类实例的未定义属性,则编译器不生成错误。

4.函数语句和函数表达式区别

函数表达式不像对象那样独立存在。如果该函数表达式所附加到的数组或对象脱离作用域或由于其它原因不再可用,您将无法再访问该函数表达式。如果删除该数组或对象,该函数表达式所使用的内存将符合垃圾回收条件。但是函数语句则是独立存在的。

dynamic class Test {}
var myTest:Test = new Test();
// function statement
function stateFunc() { trace("Function statement") }
myTest.statement = stateFunc;
myTest.statement(); // Function statement
delete myTest.statement;
delete stateFunc; // no effect
stateFunc();// Function statement
myTest.statement(); // error

第二个区别是,函数语句存在于定义它们的整个作用域(包括出现在该函数语句前面的语句)内。与之相反,函数表达式只是为后续的语句定义的。

5.嵌套函数

您可以嵌套函数,这意味着函数可以在其它函数内部声明。除非将对嵌套函数的引用传递给外部代码,否则嵌套函数将仅在其父函数内可用。 

function getNameAndVersion():String
{
    function getVersion():String
    {
       return "10";
    }

    function getProductName():String
    {
       return "Flash Player";
    }

    return (getProductName() + " " + getVersion());
}
trace(getNameAndVersion()); // Flash Player 10

 6.按值或按引用传递参数

在 AS3.0 中,所有的参数均按引用传递,因为所有的值都存储为对象。但是,属于基元数据类型(包括 Boolean、Number、int、uint 和 String)的对象具有一些特殊运算符,这使它们可以像按值传递一样工作。引用是否可以指向一个新的对象呢?

7.默认参数

所有具有默认值的参数都必须放在参数列表的末尾。指定为默认值的值必须是编译时常量。如果某个参数存在默认值,其效果会使该参数成为可选参数。没有默认值的参数被视为必需参数。

8.arguments 对象
在将参数传递给某个函数时,可以使用 arguments 对象来访问有关传递给该函数的参数的信息。
如果将任何参数命名为 arguments,或者使用 ...(rest) 参数,则 arguments 对象不可用。 

function traceArgArray(x:int):void
{
for (var i:uint = 0; i < arguments.length; i++)
{
trace(arguments[i]);
}
}
traceArgArray(1, 2, 3);
// output:
// 1
// 2
// 3

arguments.callee 属性通常用在匿名函数中以创建递归。如果递归函数的名称在开发周期内的不同阶段会发生改变,而且您使用的是 arguments.callee (而非函数名),则不必花费精力在函数体内更改递归调用。下面的函数表达式中使用 arguments.callee 属性来启用递归:

var factorial:Function = function (x:uint)
{
    if(x == 0)
    {
        return 1;
    }
    else
    {
        return (x * arguments.callee(x - 1));
    }
}
trace(factorial(5)); // 120

 9.... (rest) 参数

此参数可用来指定一个数组参数以接受任意多个以逗号分隔的参数。参数可以拥有保留字以外的任意名称。此参数声明必须是最后一个指定的参数。使用此参数会使 arguments 对象不可用。... (rest) 参数还可与其它参数一起使用,第一个参数 x 是 int 类型,第二个参数使用 ... (rest) 参数。输出结果会忽略第一个值,因为第一个参数不再属于由
...(rest) 参数创建的数组。

function traceArgArray(x: int, ... args)
{
    for (var i:uint = 0; i < args.length; i++)
    {
         trace(args[i]);
    }
}
traceArgArray(1, 2, 3);
// output:
// 2
// 3

10.函数作为对象

在标准模式下,可以通过在函数体外部定义函数属性来定义您自己的函数属性。函数属性可以用作准静态属性,用来保存与该函数有关的变量的状态。例如,您可能希望跟踪对特定函数的调用次数。如果您正在编写游戏,并且希望跟踪用户使用特定命令的次数,则这样的功能会非常有用,尽管您也可以使用静态类属性来实现此目的。

// Compiles only in standard mode
var someFunction:Function = function ():void
{
    someFunction.counter++;
}
someFunction.counter = 0;
someFunction();
someFunction();
trace(someFunction.counter); // 2

11.函数作用域

作用域链
无论何时开始执行函数,都会创建许多对象和属性。首先,会创建一个称为激活对象 的特殊对象,该对象用于存储在函数体内声明的参数以及任何局部变量或函数。由于激活对象属于内部机制,因此您无法直接访问它。接着,会创建一个范围链,其中包含由 Flash Player 或 Adobe AIR 检查标识符声明的对象的有序列表。所执行的每个函数都有一个存储在内部属性中的作用域链。对于嵌套函数,范围链始于其自己的激活对象,后跟其父函数的激活对象。作用域链以这种方式延伸,直到到达全局对象。全局对象是在 ActionScript 程序开始时创建的,其中包含所有的全局变量和函数。

函数闭包
函数闭包 是一个对象,其中包含函数的快照及其“ 词汇环境”。函数的词汇环境包括函数范围链中的所有变量、属性、方法和对象以及它们的值。无论何时在对象或类之外的位置执行函数,都会创建函数闭包。函数闭包保留定义它们的作用域,这样,在将函数作为参数或返回值传递给另一个作用域时,会产生有趣的结果。

function foo():Function
{
    var x:int = 40;
    function rectArea(y:int):int // function closure defined
    {
        return x * y
    }
    return rectArea;
}
function bar():void
{
    var x:int = 2;
    var y:int = 4;
    var myProduct:Function = foo();
    trace(myProduct(4)); // function closure called
}
bar(); // 160

函数闭包与绑定方法之间的主要区别在于,绑定方法中 this 关键字的值始终引用它最初附加到的实例,而函数闭包中 this 关键字的值可以改变。

 

 

 

posted @ 2012-04-22 00:10  jinc  阅读(1331)  评论(0编辑  收藏  举报