Basic function concepts

This section discusses basic function definition and invocation techniques.

Calling functions

You call a function by using its identifier followed by the parentheses operator ( () ). You use the parentheses operator to enclose any function parameters you want to send to the function. For example, the trace() function, which is a top-level function in ActionScript 3.0, is used throughout this book:

trace("Use trace to help debug your script");

If you are calling a function with no parameters, you must use an empty pair of parentheses. For example, you can use the Math.random() method, which takes no parameters, to generate a random number:

var randomNum:Number = Math.random();

Defining your own functions

There are two ways to define a function in ActionScript 3.0: you can use a function statement or a function expression. The technique you choose depends on whether you prefer a more static or dynamic programming style. Define your functions with function statements if you prefer static, or strict mode, programming. Define your functions with function expressions if you have a specific need to do so. Function expressions are more often used in dynamic, or standard mode, programming.

Function statements

Function statements are the preferred technique for defining functions in strict mode. A function statement begins with the function keyword, followed by:

  • The function name

  • The parameters, in a comma-delimited list enclosed in parentheses

  • The function body—that is, the ActionScript code to be executed when the function is invoked, enclosed in curly braces

    For example, the following code creates a function that defines a parameter and then invokes the function using the string “ hello" as the parameter value:

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

Function expressions

The second way to declare a function is to use an assignment statement with a function expression, which is also sometimes called a function literal or an anonymous function. This is a more verbose method that is widely used in earlier versions of ActionScript.

An assignment statement with a function expression begins with the var keyword, followed by:

  • The function name

  • The colon operator ( : )

  • The Function class to indicate the data type

  • The assignment operator ( = )

  • The function keyword

  • The parameters, in a comma-delimited list enclosed in parentheses

  • The function body—that is, the ActionScript code to be executed when the function is invoked, enclosed in curly braces

    For example, the following code declares the traceParameter function using a function expression:

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

    Notice that you do not specify a function name, as you do in a function statement. Another important difference between function expressions and function statements is that a function expression is an expression rather than a statement. This means that a function expression cannot stand on its own as a function statement can. A function expression can be used only as a part of a statement, usually an assignment statement. The following example shows a function expression assigned to an array element:

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

Choosing between statements and expressions

As a general rule, use a function statement unless specific circumstances call for the use of an expression. Function statements are less verbose, and they provide a more consistent experience between strict mode and standard mode than function expressions.

Function statements are easier to read than assignment statements that contain function expressions. Function statements make your code more concise; they are less confusing than function expressions, which require you to use both the var and function keywords.

Function statements provide a more consistent experience between the two compiler modes in that you can use dot syntax in both strict and standard mode to invoke a method declared using a function statement. This is not necessarily true for methods declared with a function expression. For example, the following code defines a class named Example with two methods: methodExpression() , which is declared with a function expression, and methodStatement() , which is declared with a function statement. In strict mode, you cannot use dot syntax to invoke the methodExpression() method.

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

Function expressions are considered better suited to programming that focuses on run-time, or dynamic, behavior. If you prefer to use strict mode, but also need to call a method declared with a function expression, you can use either of two techniques. First, you can call the method using square brackets ( [] ) instead of the dot ( . ) operator. The following method call succeeds in both strict mode and standard mode:

myExample["methodLiteral"]();

Second, you can declare the entire class as a dynamic class. Although this allows you to call the method using the dot operator, the downside is that you sacrifice some strict mode functionality for all instances of that class. For example, the compiler does not generate an error if you attempt to access an undefined property on an instance of a dynamic class.

There are some circumstances in which function expressions are useful. One common use of function expressions is for functions that are used only once and then discarded. Another less common use is for attaching a function to a prototype property. For more information, see The prototype object.

There are two subtle differences between function statements and function expressions that you should take into account when choosing which technique to use. The first difference is that function expressions do not exist independently as objects with regard to memory management and garbage collection. In other words, when you assign a function expression to another object, such as an array element or an object property, you create the only reference to that function expression in your code. If the array or object to which your function expression is attached goes out of scope or is otherwise no longer available, you will no longer have access to the function expression. If the array or object is deleted, the memory that the function expression uses will become eligible for garbage collection, which means that the memory is eligible to be reclaimed and reused for other purposes.

The following example shows that for a function expression, once the property to which the expression is assigned is deleted, the function is no longer available. The class Test is dynamic, which means that you can add a property named functionExp that holds a function expression. The functionExp() function can be called with the dot operator, but once the functionExp property is deleted, the function is no longer accessible.

dynamic class Test {} 
var myTest:Test = new Test(); 
 
// function expression  
myTest.functionExp = function () { trace("Function expression") }; 
myTest.functionExp(); // Function expression 
delete myTest.functionExp; 
myTest.functionExp(); // error

If, on the other hand, the function is first defined with a function statement, it exists as its own object and continues to exist even after you delete the property to which it is attached. The delete operator only works on properties of objects, so even a call to delete the function stateFunc() itself does not work.

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

The second difference between function statements and function expressions is that function statements exist throughout the scope in which they are defined, including in statements that appear before the function statement. Function expressions, by contrast, are defined only for subsequent statements. For example, the following code successfully calls the scopeTest() function before it is defined:

statementTest(); // statementTest 
 
function statementTest():void 
{ 
    trace("statementTest"); 
}

Function expressions are not available before they are defined, so the following code results in a run-time error:

expressionTest(); // run-time error 
 
var expressionTest:Function = function () 
{ 
    trace("expressionTest"); 
}

Returning values from functions

To return a value from your function, use the return statement followed by the expression or literal value that you want to return. For example, the following code returns an expression representing the parameter:

function doubleNum(baseNum:int):int 
{ 
    return (baseNum * 2); 
}

Notice that the return statement terminates the function, so that any statements below a return statement will not be executed, as follows:

function doubleNum(baseNum:int):int { 
    return (baseNum * 2); 
    trace("after return"); // This trace statement will not be executed. 
}

In strict mode, you must return a value of the appropriate type if you choose to specify a return type. For example, the following code generates an error in strict mode, because it does not return a valid value:

function doubleNum(baseNum:int):int 
{ 
    trace("after return"); 
}

Nested functions

You can nest functions, which means that functions can be declared within other functions. A nested function is available only within its parent function unless a reference to the function is passed to external code. For example, the following code declares two nested functions inside the getNameAndVersion() function:

function getNameAndVersion():String 
{ 
    function getVersion():String 
    { 
        return "10"; 
    } 
    function getProductName():String 
    { 
        return "Flash Player"; 
    } 
    return (getProductName() + " " + getVersion()); 
} 
trace(getNameAndVersion()); // Flash Player 10

When nested functions are passed to external code, they are passed as function closures, which means that the function retains any definitions that are in scope when the function is defined. For more information, see Function scope.