함수

함수는 특정 작업을 수행하는 코드 블록이며 프로그램에서 다시 사용할 수 있습니다. ActionScript 3.0에는 메서드함수 클로저라는 두 가지 함수가 있습니다. 함수가 정의된 컨텍스트에 따라 함수를 메서드 또는 함수 클로저라고 부릅니다. 함수를 클래스 정의의 일부로 정의하거나 객체의 인스턴스에 추가한 경우 이 함수를 메서드라고 합니다. 이와 다른 방식으로 함수를 정의한 경우 이 함수를 함수 클로저라고 합니다.

ActionScript에서 함수는 항상 매우 중요한 역할을 수행해 왔습니다. 예를 들어 ActionScript 1.0에서는 class 키워드가 없어 생성자 함수에 의해 "클래스"가 정의되었습니다. 언어에 class 키워드가 추가되었지만 언어에서 제공하는 모든 기능을 활용하려면 함수를 확실하게 이해하는 것이 여전히 중요합니다. ActionScript 함수가 C++ 또는 Java와 같은 언어에서 제공되는 함수와 유사하게 동작할 것이라고 예상하는 프로그래머에게는 ActionScript 함수를 이해하는 것이 어려운 과제일 수 있습니다. 숙련된 프로그래머에게는 기본 함수 정의 및 호출이 어렵지 않을 수 있지만 ActionScript 함수의 일부 고급 기능에 대해서는 설명이 필요합니다.

기본 함수 개념

함수 호출

함수 식별자 뒤에 괄호 연산자(())를 사용하여 함수를 호출합니다. 함수에 전달하려는 모든 함수 매개 변수를 괄호 연산자를 사용하여 묶습니다. 예를 들어 trace() 함수는 ActionScript 3.0에서 최상위 함수 중 하나입니다.

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

매개 변수 없이 함수를 호출하려면 비어 있는 괄호를 사용해야 합니다. 예를 들어 매개 변수를 사용하지 않는 Math.random() 메서드를 사용하여 임의의 숫자를 생성합니다.

var randomNum:Number = Math.random();

함수 정의

ActionScript 3.0에서는 함수 명령문을 사용하거나 함수 표현식을 사용하는 두 가지 방법으로 함수를 정의합니다. 정적 또는 동적인 프로그래밍 스타일 중 선호하는 스타일에 따라 방법을 선택합니다. 정적 또는 엄격 모드의 프로그래밍을 선호하는 경우 함수 명령문을 사용하여 함수를 정의합니다. 특정한 요구에 함수 표현식이 적합하면 함수 표현식을 사용하여 함수를 정의합니다. 함수 표현식은 주로 동적 또는 표준 모드의 프로그래밍에 사용됩니다.

함수 명령문

함수 명령문은 엄격 모드에서 함수를 정의할 때 주로 이용하는 방법입니다. 함수 명령문은 function 키워드로 시작하며 그 뒤에 다음이 추가됩니다.

  • 함수 이름

  • 괄호 안에 쉼표로 구분된 목록의 매개 변수

  • 함수 본문, 즉 함수를 호출하면 실행되는 중괄호로 묶인 ActionScript 코드

예를 들어 다음 코드에서는 매개 변수가 정의된 함수를 만든 다음 매개 변수 값으로 "hello" 문자열을 사용하여 함수를 호출합니다.

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

함수 표현식

함수를 선언하는 두 번째 방법은 함수 리터럴 또는 익명 함수라고도 하는 함수 표현식이 포함된 대입문을 사용하는 것입니다. 이는 이전 버전의 ActionScript에서 많이 사용했던 방식으로 함수 명령문을 사용하는 방식에 비해 코드가 길어집니다.

함수 표현식이 포함된 대입문은 var 키워드로 시작하며 그 뒤에 다음이 추가됩니다.

  • 함수 이름

  • 콜론 연산자(:)

  • 데이터 유형을 나타내는 Function 클래스

  • 대입 연산자(=)

  • function 키워드

  • 괄호 안에 쉼표로 구분된 목록의 매개 변수

  • 함수 본문, 즉 함수를 호출하면 실행되는 중괄호로 묶인 ActionScript 코드

    예를 들어 다음 코드는 함수 표현식을 사용하여 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");

명령문과 표현식 간에 선택

일반적으로 특정 상황에서 표현식이 필요하지 않은 경우 함수 명령문을 사용합니다. 함수 명령문이 상대적으로 간단하며 엄격 모드와 표준 모드에서 함수 표현식보다 일관성 있게 사용할 수 있습니다.

함수 명령문은 함수 표현식이 포함된 대입문보다 쉽게 읽을 수 있습니다. 함수 명령문은 코드를 더욱 간결하게 만들어 varfunction 키워드를 모두 사용해야 하는 함수 표현식보다 혼란을 덜 초래합니다.

함수 명령문을 사용하여 선언된 메서드를 호출할 때 엄격 모드와 표준 모드 모두에서 도트 구문을 사용할 수 있다는 점에서 함수 명령문은 두 컴파일러 모드 간의 일관성이 함수 표현식보다 낫습니다. 함수 표현식으로 선언된 메서드의 경우 도트 구문을 사용하여 호출하지 못할 수도 있습니다. 예를 들어 다음 코드에서는 함수 표현식으로 선언된 methodExpression() 메서드와 함수 명령문으로 선언된 methodStatement() 메서드가 있는 Example 클래스를 정의합니다. 엄격 모드에서는 methodExpression() 메서드를 호출하기 위해 도트 구문을 사용할 수 없습니다.

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"]();

두 번째, 전체 클래스를 동적 클래스로 선언할 수 있습니다. 이렇게 하면 도트 연산자를 사용하여 메서드를 호출할 수 있지만 해당 클래스의 모든 인스턴스에 대한 엄격 모드 기능의 일부가 제대로 작동하지 않을 수 있습니다. 예를 들어 동적 클래스의 인스턴스의 정의되지 않은 속성에 액세스하려고 하는 경우 컴파일러에서 오류를 생성하지 않습니다.

함수 표현식을 사용하는 것이 유용한 경우도 있습니다. 함수 표현식은 한 번만 사용하고 폐기할 함수를 정의하는 경우에 일반적으로 사용됩니다. 이보다 사용 빈도는 낮지만 프로토타입 속성에 함수를 연결하는 경우에도 사용됩니다. 자세한 내용은 프로토타입 객체를 참조하십시오.

사용할 방법을 선택할 때는 함수 명령문과 함수 표현식 간의 두 가지 미세한 차이점을 고려해야 합니다. 첫 번째 차이점은 메모리 관리 및 가비지 컬렉션과 관련해서 함수 표현식은 독립된 객체가 아니라는 점입니다. 즉, 배열 요소 또는 객체 속성과 같은 다른 객체에 함수 표현식을 지정할 때는 코드에서 해당 함수 표현식에 대한 참조만 만듭니다. 함수 표현식이 연결된 배열 또는 객체가 범위를 벗어나거나 더 이상 사용할 수 없는 경우 함수 표현식에 더 이상 액세스할 수 없습니다. 배열 또는 객체를 삭제하면 함수 표현식에서 사용하는 메모리가 가비지 컬렉션의 대상이 되므로 해당 메모리를 다른 용도로 이용하거나 재사용할 수 있습니다.

다음 예제에서는 함수 표현식의 경우 표현식이 지정된 속성이 삭제되면 함수를 더 이상 사용할 수 없다는 것을 보여 줍니다. Test 클래스는 동적이므로 함수 표현식이 저장된 functionExp 속성을 추가할 수 있습니다. 도트 연산자를 사용하여 functionExp() 함수를 호출할 수 있지만 functionExp 속성이 삭제되면 더 이상 함수에 액세스할 수 없습니다.

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

반면에 먼저 함수 명령문으로 함수를 정의하면 이 함수는 독립된 객체로 존재하며 함수가 연결된 속성을 삭제한 후에도 계속해서 사용할 수 있습니다. delete 연산자는 객체의 속성에 대해서만 작동하므로 stateFunc() 함수 자체를 삭제하는 호출도 작동하지 않습니다.

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

함수 명령문과 함수 표현식 간의 두 번째 차이점은 함수 명령문은 함수 명령문 앞에 나오는 명령문을 포함하여 함수 명령문이 정의된 범위 전체에서 사용된다는 점입니다. 반면에 함수 표현식은 후속 명령문에 대해서만 정의됩니다. 예를 들어 다음 코드에서는 scopeTest() 함수를 정의하기 전에 해당 함수를 성공적으로 호출합니다.

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

함수 표현식은 정의하기 전에 사용할 수 없기 때문에 다음 코드에서 런타임 오류가 발생합니다.

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

함수에서 값 반환

함수에서 값을 반환하려면 return 문 다음에 반환할 표현식 또는 리터럴 값을 지정합니다. 예를 들어 다음 코드는 매개 변수를 나타내는 표현식을 반환합니다.

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

return 문은 함수를 종료하므로 다음과 같이 return 문 아래의 명령문이 모두 실행되지 않습니다.

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

반환 유형을 지정하기로 결정한 경우 엄격 모드에서는 적절한 유형의 값을 반환해야 합니다. 예를 들어 다음 코드에서는 올바른 값을 반환하지 않기 때문에 엄격 모드에서 오류가 발생합니다.

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

중첩 함수

함수를 중첩할 수 있으므로 다른 함수 내에 함수를 선언할 수 있습니다. 함수에 대한 참조가 외부 코드로 전달되지 않으면 중첩 함수는 부모 함수 내에서만 사용할 수 있습니다. 예를 들어 다음 코드는 getNameAndVersion() 함수 내에 두 개의 중첩 함수를 선언합니다.

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

중첩 함수가 외부 코드로 전달되면 해당 함수는 함수 클로저로 전달되므로 함수가 정의될 때 범위에 있는 모든 정의가 함수에 그대로 유지됩니다. 자세한 내용은 함수 범위를 참조하십시오.

함수 매개 변수

ActionScript 3.0의 함수 매개 변수에는 이 언어를 처음 접하는 프로그래머에게는 신기할 수 있는 몇 가지 기능이 있습니다. 대부분의 프로그래머는 값 또는 참조에 의한 매개 변수 전달이라는 개념에 익숙하지만 arguments 객체 및 ... (rest) 매개 변수에는 익숙하지 않을 수 있습니다.

값 또는 참조에 의한 인수 전달

여러 프로그래밍 언어에서 값에 의한 인수 전달과 참조에 의한 인수 전달 간의 차이점은 코드를 설계하는 방법에 영향을 미칠 수 있기 때문에 잘 이해해야 합니다.

값에 의한 전달은 인수 값이 함수 내에서 사용할 로컬 변수에 복사되는 것을 의미합니다. 참조에 의한 전달은 실제 값 대신 인수에 대한 참조만 전달되는 것을 의미합니다. 이 경우 실제 인수가 복사되지는 않습니다. 대신 인수로 전달된 변수에 대한 참조가 만들어져 함수 내에서 사용할 로컬 변수에 지정됩니다. 로컬 변수를 함수 외부의 변수에 대한 참조로 사용하여 원본 변수의 값을 변경할 수 있습니다.

ActionScript 3.0에서는 모든 값이 객체로 저장되므로 모든 인수가 참조를 기준으로 전달됩니다. 그러나 Boolean, Number, int, uint 및 String 등이 포함된 프리미티브 데이터 유형에 속한 객체에는 값을 기준으로 전달된 것과 같이 동작하도록 하는 특수 연산자가 있습니다. 예를 들어 다음 코드에서는 xParamyParam이라고 하는 int 유형의 두 매개 변수를 정의하는 passPrimitives() 함수를 만듭니다. 이러한 매개 변수는 passPrimitives() 함수 본문 내에 선언된 로컬 변수와 유사합니다. xValueyValue 인수를 사용하여 함수를 호출하면 xParamyParam 매개 변수는 xValueyValue로 표시되는 int 객체에 대한 참조로 초기화됩니다. 인수가 프리미티브 값이기 때문에 값을 기준으로 전달된 것처럼 동작합니다. 처음에는 xParamyParamxValueyValue 객체에 대한 참조만 포함되지만 함수 본문 내에서 xParam 및 yParam의 값을 변경하면 메모리에 새 값의 복사본이 생성됩니다.

function passPrimitives(xParam:int, yParam:int):void 
{ 
    xParam++; 
    yParam++; 
    trace(xParam, yParam); 
} 
 
var xValue:int = 10; 
var yValue:int = 15; 
trace(xValue, yValue);// 10 15 
passPrimitives(xValue, yValue); // 11 16 
trace(xValue, yValue);// 10 15

passPrimitives() 함수 내에서는 xParamyParam의 값이 증가되지만 마지막 trace 문에서와 같이 xValueyValue의 값에는 영향을 주지 않습니다. 함수 내에 있는 xValueyValue는 함수 외부에 있는 동일한 이름의 변수와 별개로 존재하는 메모리의 새 위치를 가리키기 때문에 매개 변수가 xValueyValue 변수와 이름이 동일한 경우에도 영향을 미치지 않습니다.

프리미티브 데이터 유형에 속하지 않은 다른 모든 객체는 항상 참조로 전달되므로 원본 변수의 값을 변경할 수 있습니다. 예를 들어 다음 코드에서는 xy라는 두 가지 속성이 있는 objVar 객체를 만듭니다. 이 객체는 passByRef() 함수에 인수로 전달됩니다. 이 객체는 프리미티브 유형이 아니기 때문에 참조를 기준으로 전달될 뿐만 아니라 참조를 유지합니다. 즉, 함수 내에 있는 매개 변수가 변경되면 함수 외부의 객체 속성에도 적용됩니다.

function passByRef(objParam:Object):void 
{ 
    objParam.x++; 
    objParam.y++; 
    trace(objParam.x, objParam.y); 
} 
var objVar:Object = {x:10, y:15}; 
trace(objVar.x, objVar.y); // 10 15 
passByRef(objVar); // 11 16 
trace(objVar.x, objVar.y); // 11 16

objParam 매개 변수가 objVar 전역 변수와 동일한 객체를 참조합니다. 예제의 trace 문에서 볼 수 있듯이 objParam 객체의 xy 속성을 변경하면 objVar 객체에 반영됩니다.

매개 변수 기본값

ActionScript 3.0에서는 함수의 매개 변수 기본값을 선언할 수 있습니다. 매개 변수 기본값이 있는 함수를 호출할 때 기본값이 있는 매개 변수를 생략하면 해당 매개 변수에 대해 함수 정의에 지정된 값이 사용됩니다. 기본값이 있는 모든 매개 변수는 매개 변수 목록의 끝에 배치해야 합니다. 기본값으로 지정된 값은 컴파일 타임 상수여야 합니다. 매개 변수에 대해 기본값을 사용하여 매개 변수를 효과적으로 선택적 매개 변수로 만들 수 있습니다. 기본값이 없는 매개 변수는 필수 매개 변수로 간주됩니다.

예를 들어 다음 코드는 세 개의 매개 변수가 있는 함수를 만들며 이 중 두 매개 변수에는 기본값이 있습니다. 하나의 매개 변수만 사용하여 함수를 호출하면 나머지 매개 변수에는 기본값이 사용됩니다.

function defaultValues(x:int, y:int = 3, z:int = 5):void 
{ 
    trace(x, y, z); 
} 
defaultValues(1); // 1 3 5

arguments 객체

함수에 인수가 전달되면 arguments 객체를 사용하여 함수에 전달된 매개 변수에 대한 정보에 액세스할 수 있습니다. arguments 객체의 중요한 특징은 다음과 같습니다.

  • arguments 객체는 함수에 전달된 매개 변수를 모두 포함하는 배열입니다.

  • arguments.length 속성은 함수에 전달된 매개 변수의 수를 보고합니다.

  • arguments.callee 속성은 함수 자체에 대한 참조를 제공하며 이는 함수 표현식에 대한 재귀 호출에 유용합니다.

    참고: arguments 객체는 이름이 arguments인 매개 변수가 있거나 사용자가 ... (rest) 매개 변수를 사용하는 경우 사용할 수 없습니다.

    함수 본문에서 arguments 객체를 참조하는 경우 ActionScript 3.0에서는 함수 정의에 정의된 매개 변수보다 많은 매개 변수를 사용하여 함수를 호출할 수 있지만, 매개 변수의 수가 필수 매개 변수(경우에 따라 모든 선택적 매개 변수도 포함)의 수와 일치하지 않으면 엄격 모드에서 컴파일러 오류가 발생합니다. arguments 객체를 배열로 사용하면 해당 매개 변수가 함수 정의에 정의되어 있는지 여부에 관계없이 함수에 전달된 모든 매개 변수에 액세스할 수 있습니다. 다음은 arguments.length 속성과 함께 arguments 배열을 사용하여 traceArgArray() 함수에 전달된 매개 변수를 모두 추적하는 예제입니다. 이 예제는 표준 모드에서만 컴파일됩니다.

    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

    함수 선언에서 ...(rest) 매개 변수를 사용하면 arguments 객체는 사용할 수 없습니다. 대신 선언한 매개 변수 이름을 사용하여 매개 변수에 액세스해야 합니다.

    또한 매개 변수 이름으로 "arguments" 문자열을 사용하면 arguments 객체가 가려지므로 이렇게 사용하지 않는 것이 좋습니다. 예를 들어 traceArgArray() 함수가 다시 작성되어 arguments 매개 변수가 추가되는 경우 함수 본문에 있는 arguments에 대한 참조를 사용하면 arguments 객체가 아닌 매개 변수를 참조하게 됩니다. 다음 코드는 출력을 생성하지 않습니다.

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

    이전 버전의 ActionScript에 있는 arguments 객체에는 현재 함수를 호출한 함수에 대한 참조인 caller 속성도 포함되어 있습니다. ActionScript 3.0에는 caller 속성이 없지만 호출 함수에 대한 참조가 필요한 경우 호출 함수 자체에 대한 참조인 추가 매개 변수가 전달되도록 호출 함수를 변경할 수 있습니다.

... (rest) 매개 변수

ActionScript 3.0에는 ... (rest) 매개 변수라는 새 매개 변수 선언이 도입되었습니다. 이 매개 변수를 사용하면 쉼표로 구분된 인수를 무제한으로 받아들이는 배열 매개 변수를 지정할 수 있습니다. 매개 변수는 예약어가 아닌 어떤 이름이나 가질 수 있습니다. 이 매개 변수 선언은 마지막으로 지정된 매개 변수여야 합니다. 이 매개 변수를 사용하면 arguments 객체를 사용할 수 없습니다. ... (rest) 매개 변수는 arguments 배열 및 arguments.length 속성과 동일한 기능을 제공하지만 arguments.callee와 유사한 기능은 제공하지 않습니다. ... (rest) 매개 변수를 사용하기 전에 arguments.callee를 사용할 필요가 없는지 확인해야 합니다.

다음은 traceArgArray() 함수를 다시 작성하기 위해 arguments 객체 대신 ... (rest) 매개 변수를 사용하는 예제입니다.

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

... (rest) 매개 변수가 마지막으로 나열되기만 하면 다른 매개 변수와 함께 사용할 수도 있습니다. 다음은 traceArgArray() 함수를 수정하여 int 유형의 x를 첫 번째 매개 변수로 사용하고 ... (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

객체와 같은 함수

ActionScript 3.0에서 함수는 객체입니다. 함수를 만드는 것은 객체를 만드는 것을 의미합니다. 이 객체는 다른 함수에 매개 변수로 전달될 수 있을 뿐만 아니라 다른 함수에 연결된 속성 및 메서드를 가질 수도 있습니다.

다른 함수에 인수로 전달된 함수는 값이 아닌 참조를 기준으로 전달됩니다. 함수를 인수로 전달하는 경우 식별자만 사용하며 메서드를 호출하는 데 사용하는 괄호 연산자는 사용하지 않습니다. 예를 들어 다음 코드는 clickListener() 함수를 addEventListener() 메서드에 인수로 전달합니다.

addEventListener(MouseEvent.CLICK, clickListener);

ActionScript를 처음 접하는 프로그래머에게는 이상하게 보일 수 있지만 함수는 다른 모든 객체와 같이 속성과 메서드를 가질 수 있습니다. 실제로 모든 함수에는 해당 함수에 대해 정의된 매개 변수의 수를 저장하는 length라는 읽기 전용 속성이 있습니다. 이 속성은 함수에 전달된 인수의 수를 보고하는 arguments.length 속성과는 다릅니다. ActionScript에서는 함수에 전달된 인수의 수가 해당 함수에 대해 정의된 매개 변수의 수를 초과할 수 있음을 상기하십시오. 다음 예제에서 두 속성 간의 차이점을 보여 줍니다. 이 예제의 경우 엄격 모드에서는 전달된 인수의 수와 정의된 매개 변수의 수가 정확하게 일치해야 하므로 표준 모드에서만 컴파일됩니다.

// Compiles only in standard mode 
function traceLength(x:uint, y:uint):void 
{ 
    trace("arguments received: " + arguments.length); 
    trace("arguments expected: " + traceLength.length); 
} 
 
traceLength(3, 5, 7, 11); 
/* output: 
arguments received: 4 
arguments expected: 2 */

표준 모드에서 함수 본문 외부에 함수 속성을 정의하는 방법으로 함수 속성을 직접 정의할 수 있습니다. 함수 속성은 함수와 연관된 변수의 상태를 저장할 수 있는 준 정적 속성 역할을 수행할 수 있습니다. 예를 들어 특정 함수가 호출된 횟수를 추적할 수 있습니다. 사용자의 특정 명령 사용 횟수를 추적하는 기능이 있는 게임을 작성하는 경우 정적 클래스 속성을 사용할 수도 있지만 함수 호출 횟수를 추적하는 기능이 유용할 수 있습니다. 다음은 함수 선언 외부에서 함수 속성을 만들고 함수가 호출될 때마다 속성을 증가시키는 예제입니다. 엄격 모드에서는 함수에 동적 속성을 추가할 수 없기 때문에 이 예제는 표준 모드에서만 컴파일됩니다.

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

함수 범위

함수 범위는 함수를 호출할 수 있는 프로그램의 위치뿐만 아니라 함수가 액세스할 수 있는 정의를 결정합니다. 변수 식별자에 적용되는 동일한 범위 규칙이 함수 식별자에 적용됩니다. 전역 범위에 선언된 함수는 코드 전체에 사용할 수 있습니다. 예를 들어 ActionScript 3.0에는 코드의 어느 위치에서든 사용할 수 있는 isNaN()parseInt() 등의 전역 함수가 포함되어 있습니다. 다른 함수 내에 선언된 중첩 함수는 선언된 함수 내의 어느 곳에서나 사용할 수 있습니다.

범위 체인

함수가 실행되면 여러 객체와 속성이 만들어집니다. 첫 번째, 함수 본문에 선언된 함수나 로컬 변수 및 매개 변수를 저장하는 activation 객체라는 특수 객체가 만들어집니다. activation 객체는 내부 메커니즘이므로 직접 액세스할 수 없습니다. 두 번째, 런타임에서 식별자 선언을 찾을 때 확인하는 정렬된 객체 목록이 포함되어 있는 범위 체인이 만들어집니다. 실행되는 모든 함수의 내부 속성에 범위 체인이 저장됩니다. 중첩 함수의 범위 체인은 중첩 함수의 activation 객체에서 시작하여 부모 함수의 activation 객체로 이어집니다. 전역 객체에 도달할 때까지 이러한 방식으로 체인이 계속됩니다. ActionScript 프로그램이 시작되고 모든 전역 변수 및 함수가 포함되면 전역 객체가 만들어집니다.

함수 클로저

함수 클로저는 함수의 스냅샷 및 사전적 환경이 포함된 객체입니다. 함수의 사전적 환경에는 함수 범위 체인에 있는 모든 변수, 속성, 메서드 및 객체가 해당 값과 함께 포함됩니다. 함수 클로저는 객체 또는 클래스와는 별도로 함수가 실행될 때 만들어집니다. 자신이 정의된 범위를 유지하는 함수 클로저로 인해 함수가 인수 또는 반환 값으로 다른 범위로 전달될 때 흥미로운 결과가 나타납니다.

예를 들어 다음 코드는 두 개의 함수를 만듭니다. foo()는 사각형의 면적을 계산하는 rectArea()라는 중첩된 함수를 반환하고, bar()foo()를 호출하고 반환된 함수 클로저를 myProduct 변수에 저장합니다. bar() 함수에서 로컬 변수 x를 값 2로 정의하지만 함수 클로저 myProduct()를 호출하면 함수 클로저에서는 foo() 함수에 정의된 변수 x (값 40)가 그대로 유지됩니다. 따라서 bar() 함수에서 8 대신 160을 반환합니다.

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 키워드 값은 변경할 수 있다는 것입니다.