Funzioni

Le funzioni sono blocchi di codice che eseguono operazioni specifiche e possono essere riutilizzati all'interno del programma. In ActionScript 3.0 sono disponibili due tipi di funzioni: metodi e chiusure di funzione. Una funzione viene chiamata metodo oppure chiusura di funzione a seconda del contesto nel quale è definita. Se la funzione viene definita all'interno di una definizione di classe o associata a un'istanza di un oggetto, prende il nome di metodo. Se viene definita in qualunque altro modo, viene chiamata chiusura di funzione.

Le funzioni hanno sempre avuto un ruolo estremamente importante in ActionScript. In ActionScript 1.0, ad esempio, la parola chiave class non esisteva, quindi le “classi” erano definite dalle funzioni di costruzione. Anche se nel frattempo la parola chiave class è stata aggiunta al linguaggio, una conoscenza approfondita delle funzioni è ancora importante per sfruttare nel modo migliore le possibilità offerte da ActionScript. Questo compito può risultare più impegnativo per i programmatori che si aspettano un comportamento delle funzioni ActionScript analogo a quello di linguaggi come C++ o Java. Anche se le procedure di base per definire e chiamare le funzioni non dovrebbero rappresentare un problema per i programmatori esperti, alcune delle caratteristiche più avanzate di ActionScript richiedono un approfondimento.

Concetti di base delle funzioni

Chiamate di funzione

È possibile chiamare una funzione specificando il relativo identificatore seguito dall'operatore parentesi (()). L'operatore parentesi ha il compito di racchiudere gli eventuali parametri che si desidera inviare alla funzione. Ad esempio, la funzione trace() è una funzione di primo livello in ActionScript 3.0:

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

Se chiamate una funzione senza parametri, dovete includere una coppia di parentesi vuote. Ad esempio, potete utilizzare il metodo Math.random(), che non accetta parametri, per generare un numero casuale:

var randomNum:Number = Math.random();

Definizione di funzioni personalizzate

In ActionScript 3.0 sono disponibili due metodi per definire una funzione: potete utilizzare un'istruzione di funzione o un'espressione di funzione. A seconda che preferiate uno stile di programmazione più statico o dinamico, potete scegliere una o l'altra tecnica. In genere, chi usa le istruzioni per definire le funzioni preferisce la programmazione statica (modalità rigorosa). Le espressioni vengono invece utilizzate per definire le funzioni quando esiste un'esigenza specifica in questo senso, solitamente nella programmazione dinamica (modalità standard).

Istruzioni di funzione

Le istruzioni di funzione sono la tecnica preferita per definire le funzioni in modalità rigorosa. Un'istruzione di funzione inizia con la parola chiave function, seguita da:

  • Il nome della funzione

  • I parametri, separati da virgole e racchiusi tra parentesi

  • Il corpo della funzione, ovvero il codice ActionScript da eseguire quando la funzione viene chiamata, racchiuso tra parentesi graffe

Ad esempio, il codice seguente crea una funzione che definisce un parametro, quindi chiama la funzione utilizzando la stringa “hello" come valore del parametro:

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

Espressioni di funzione

Il secondo modo per dichiarare una funzione prevede l'uso di un'istruzione di assegnazione con un'espressione di funzione, che talvolta viene anche definita letterale di funzione o funzione anonima. Si tratta di un metodo più verboso, largamente utilizzato nelle versioni precedenti di ActionScript.

Un'istruzione di assegnazione con un'espressione di funzione inizia con la parola chiave var, seguita da:

  • Il nome della funzione

  • L'operatore due punti (:)

  • La classe Function per indicare il tipo di dati

  • L'operatore di assegnazione (=)

  • La parola chiave function

  • I parametri, separati da virgole e racchiusi tra parentesi

  • Il corpo della funzione, ovvero il codice ActionScript da eseguire quando la funzione viene chiamata, racchiuso tra parentesi graffe

    Ad esempio, il codice seguente dichiara la funzione traceParameter utilizzando un'espressione di funzione:

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

    Notate che non occorre specificare un nome di funzione come avviene nelle istruzioni di funzione. Un'altra importante differenza tra le espressioni di funzione e le istruzioni di funzione consiste nel fatto che un'espressione di funzione è appunto un'espressione e non un'istruzione. Ciò significa che un'espressione di funzione, a differenza di un'istruzione di funzione, non può esistere come elemento autonomo, bensì può essere utilizzata solo all'interno di un'istruzione, solitamente un'istruzione di assegnazione. L'esempio seguente mostra un'espressione di funzione assegnata a un elemento array:

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

Scelta tra istruzioni ed espressioni

Come regola generale, utilizzate un'istruzione di funzione a meno che le circostanze specifiche non suggeriscano l'uso di un'espressione. Le istruzioni di funzione sono meno verbose e, rispetto alle espressioni di funzione, producono risultati più omogenei tra modalità rigorosa e modalità standard.

Le istruzioni di funzione sono più facili da leggere delle istruzioni di assegnazione che contengono espressioni di funzione, consentono di scrivere codice più conciso e creano meno confusione delle espressioni di funzione, che richiedono l'uso delle due parole chiave var e function.

Inoltre, le istruzioni di funzione producono risultati più omogenei tra le due modalità del compilatore perché consentono di utilizzare la sintassi del punto sia in modalità rigorosa che standard per chiamare un metodo dichiarato mediante un'istruzione di funzione, il che non è sempre possibile per i metodi dichiarati con un'espressione di funzione. Il codice seguente, ad esempio, definisce una classe denominata Example con due metodi: methodExpression(), dichiarato con un'espressione di funzione, e methodStatement(), dichiarato con un'istruzione di funzione. In modalità rigorosa non potete utilizzare la sintassi del punto per chiamare il metodo 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

Le espressioni di funzione sono generalmente più indicate per la programmazione che privilegia il comportamento runtime, ovvero dinamico. Se preferite utilizzare la modalità rigorosa ma avete anche la necessità di chiamare un metodo dichiarato con un'espressione di funzione, potete utilizzare entrambe le tecniche. Innanzi tutto, potete chiamare il metodo utilizzando le parentesi quadre ([]) invece dell'operatore punto (.). Il metodo seguente ha esito positivo sia in modalità rigorosa che standard:

myExample["methodLiteral"]();

In secondo luogo, potete dichiarare l'intera classe come classe dinamica. Sebbene in questo modo sia possibile chiamare il metodo utilizzando l'operatore punto, la funzionalità della modalità rigorosa viene parzialmente sacrificata per tutte le istanze di tale classe. Ad esempio, il compilatore non genera un errore se si tenta di accedere a una proprietà non definita su un'istanza di una classe dinamica.

In determinate circostanze le espressioni di funzione risultano utili. Un caso frequente è quello delle funzioni che vengono utilizzate una sola volta e quindi eliminate. Un altro utilizzo, meno comune, riguarda l'associazione di una funzione a una proprietà prototype. Per ulteriori informazioni, vedete Oggetto prototype.

Esistono due sottili differenze tra le istruzioni di funzione e le espressioni di funzione di cui va tenuto conto quando si sceglie la tecnica da utilizzare. La prima è che un'espressione di funzione non viene considerata come oggetto indipendente ai fini della gestione della memoria e del processo di garbage collection. In altre parole, quando si assegna un'espressione di funzione a un altro oggetto, ad esempio a un elemento di array o una proprietà di un oggetto, nel codice viene creato semplicemente un riferimento all'espressione di funzione. Se l'array o l'oggetto al quale è associata l'espressione di funzione esce dall'area di validità o comunque cessa di essere disponibile, non è più possibile accedere all'espressione. Se l'array o l'oggetto viene eliminato, la memoria utilizzata dall'espressione di funzione diventa disponibile per il processo di garbage collection, ovvero può essere riutilizzata per altri scopi.

L'esempio seguente mostra che, se viene eliminata la proprietà alla quale è assegnata un'espressione di funzione, la funzione non è più disponibile. La classe Test è dinamica e consente quindi di aggiungere una proprietà denominata functionExp che contiene un'espressione di funzione. La funzione functionExp() può essere chiamata con l'operatore punto, ma non è più accessibile dopo l'eliminazione della proprietà 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

Se, al contrario, la funzione viene inizialmente definita mediante un'istruzione di funzione, esiste come oggetto autonomo e continua a esistere anche dopo l'eliminazione della proprietà alla quale è associata. L'operatore delete funziona solo sulle proprietà degli oggetti, quindi non ha effetto se viene utilizzato per eliminare la funzione 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

La seconda differenza tra un'istruzione di funzione e un'espressione di funzione consiste nel fatto che la prima esiste in tutta l'area di validità nella quale è definita, comprese le istruzioni che la precedono. Un'espressione di funzione, al contrario, viene definita solo per le istruzioni successive. Ad esempio, il codice seguente contiene una chiamata (che ha esito positivo) alla funzione scopeTest() prima che venga definita:

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

Le espressioni di funzione non sono disponibili prima della posizione in cui vengono definite, quindi il codice seguente genera un errore runtime:

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

Restituzione di valori da funzioni

Per restituire un valore da una funzione, utilizzate l'istruzione return seguita dall'espressione o dal valore letterale da restituire. Il seguente codice, ad esempio, restituisce un'espressione corrispondente al parametro:

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

Notate che l'istruzione return termina la funzione, quindi eventuali istruzioni successive a un'istruzione return non vengono eseguite, come nell'esempio seguente:

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

In modalità rigorosa dovete restituire un valore del tipo appropriato se scegliete di specificare un tipo restituito. Ad esempio, il codice seguente genera un errore in modalità rigorosa perché non restituisce un valore valido:

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

Funzioni nidificate

È possibile nidificare le funzioni, cioè dichiararle all'interno di altre funzioni. Una funzione nidificata è disponibile solo all'interno della funzione principale in cui è contenuta, a meno che non venga passato al codice esterno un riferimento alla funzione. Ad esempio, il codice seguente dichiara due funzioni nidificate all'interno della funzione getNameAndVersion():

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

Se passate al codice esterno, le funzioni nidificate vengono passate come chiusure di funzione, vale a dire che la funzione conserva le definizioni che si trovano nell'area di validità nel momento in cui viene definita. Per ulteriori informazioni, vedete Area di validità delle funzioni.

Parametri di funzione

ActionScript 3.0 introduce alcune funzionalità relative ai parametri di funzione che potrebbero sembrare inedite ai programmatori che iniziano a utilizzare questo linguaggio. Benché l'idea di passare i parametri mediante un valore o un riferimento risulti probabilmente familiare alla maggior parte dei programmatori, l'oggetto arguments e il parametro ... (rest) potrebbero invece rappresentare una novità.

Passaggio di argomenti mediante un valore o un riferimento

In molti linguaggi di programmazione, è importante comprendere la distinzione che esiste tra passare gli argomenti mediante un valore oppure mediante un riferimento, poiché tale distinzione può influire su come viene progettato il codice.

Passare un argomento mediante un valore significa copiarne il valore in una variabile locale da utilizzare con la funzione. Al contrario, se si specifica un argomento mediante un riferimento, viene passato solo un riferimento all'argomento e non il valore effettivo. Nel secondo caso non viene quindi creata una copia dell'argomento vero e proprio, bensì viene passato come argomento un riferimento alla variabile nel momento in cui l'argomento viene creato e assegnato a una variabile locale da utilizzare nella funzione. Poiché è un riferimento a una variabile esterna alla funzione, la variabile locale consente di modificare il valore della variabile originale.

In ActionScript 3.0, tutti gli argomenti vengono passati mediante riferimento perché tutti i valori sono memorizzati come oggetti. Tuttavia, gli oggetti che appartengono ai tipi di dati di base (Boolean, Number, int, uint e String) prevedono l'uso di operatori speciali grazie ai quali possono comportarsi come se venissero passati mediante un valore. Ad esempio, il codice seguente crea una funzione denominata passPrimitives() che definisce due parametri chiamati xParam e yParam, entrambi del tipo int. Questi parametri sono simili a variabili locali dichiarate nel corpo della funzione passPrimitives(). Quando la funzione viene chiamata con gli argomenti xValue e yValue, i parametri xParam e yParam vengono inizializzati mediante riferimenti agli oggetti int rappresentati da xValue e yValue. Poiché gli argomenti appartengono a un tipo di base, si comportano come se fossero passati mediante valore. Benché xParam e yParam contengano inizialmente solo riferimenti agli oggetti xValue e yValue, qualunque modifica delle variabili all'interno del corpo della funzione genera nuove copie dei valori in memoria.

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

All'interno della funzione passPrimitives(), i valori di xParam e yParam vengono incrementati, tuttavia ciò non influisce sui valori di xValue e yValue, come mostra l'ultima istruzione trace. Lo stesso varrebbe anche nel caso in cui i parametri avessero gli stessi nomi delle variabili, xValue e yValue, perché i valori xValue e yValue all'interno della funzione farebbero riferimento a nuove posizioni di memoria, distinte dalle variabili omonime esterne alla funzione.

Tutti gli altri oggetti, ovvero gli oggetti che non appartengono ai tipi di dati primitivi, vengono sempre passati mediante riferimento, quindi con la possibilità di modificare il valore della variabile originale. Ad esempio, il codice seguente crea un oggetto denominato objVar con due proprietà, x e y. L'oggetto viene passato come argomento alla funzione passByRef(). Poiché non appartiene a un tipo di base, l'oggetto non viene semplicemente passato mediante un riferimento, ma rimane un riferimento. Ciò significa che le modifiche apportate ai parametri all'interno della funzione non hanno effetto sulle proprietà dell'oggetto all'esterno della funzione.

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

Il parametro objParam fa riferimento allo stesso oggetto della variabile globale objVar. Come potete notare nelle istruzioni trace dell'esempio, le modifiche apportate alle proprietà x e y dell'oggetto objParam vengono applicate anche all'oggetto objVar.

Valori predefiniti dei parametri

In ActionScript 3.0, potete dichiarare valori di parametro predefiniti per una funzione. Se in una chiamata a una funzione con parametri predefiniti viene omesso un parametro con valori predefiniti, viene utilizzato il valore specificato per quel parametro nella definizione della funzione. Tutti i parametri con valori predefiniti devono essere posizionati alla fine dell'elenco dei parametri. I valori assegnati come predefiniti devono essere costanti della fase di compilazione. L'esistenza di un valore predefinito per un parametro fa sì che quel parametro diventi un parametro opzionale, mentre un parametro privo di valore predefinito viene considerato un parametro obbligatorio.

Ad esempio, il codice seguente crea una funzione con tre parametri, due dei quali hanno valori predefiniti. Quando la funzione viene chiamata con un solo parametro, vengono utilizzati i valori predefiniti dei parametri.

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

L'oggetto arguments

Quando passate dei parametri a una funzione, potete utilizzare l'oggetto arguments per accedere alle informazioni relative a tali parametri. Seguono alcune osservazioni importanti relative all'oggetto arguments:

  • l'oggetto arguments è un array che include tutti i parametri passati alla funzione;

  • la proprietà arguments.length segnala il numero di parametri passati alla funzione;

  • la proprietà arguments.callee fornisce un riferimento alla funzione stessa, che è utile per le chiamate ricorsive alle espressioni di funzione.

    Nota: l'oggetto arguments non è disponibile se è presente un parametro denominato arguments oppure se utilizzate il parametro ... (rest).

    Se il corpo della funzione contiene un riferimento all'oggetto arguments, ActionScript 3.0 consente di includere nelle chiamate di funzione più parametri di quelli definiti nella definizione della funzione; tuttavia, in modalità rigorosa genera un errore del compilatore se il numero di parametri non corrisponde al numero di parametri obbligatori (e facoltativamente, qualsiasi parametro opzionale). Potete ricorrere alla funzionalità di array dell'oggetto arguments per accedere a qualunque parametro passato alla funzione, a prescindere che sia o meno definito nella definizione della funzione. L'esempio seguente, che viene compilato solo in modalità rigorosa, utilizza l'array arguments con la proprietà arguments.length per tracciare tutti i parametri passati alla funzione 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

    La proprietà arguments.callee viene spesso utilizzata nelle funzioni anonime per creare la ricorsività e rendere il codice più flessibile. Se il nome di una funzione ricorsiva cambia durante il ciclo di sviluppo, non occorre modificare la chiamata ricorsiva nel corpo della funzione se si utilizza arguments.callee al posto del nome della funzione. Nell'espressione di funzione seguente, la proprietà arguments.callee viene utilizzata per abilitare la ricorsività:

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

    Se utilizzate il parametro ... (rest) nella dichiarazione della funzione, l'oggetto arguments non è disponibile e per accedere ai parametri è necessario utilizzare i rispettivi nomi che sono stati dichiarati.

    È inoltre importante evitare di utilizzare la stringa "arguments" come nome di parametro perché impedisce l'uso dell'oggetto arguments. Ad esempio, se la funzione traceArgArray() viene riscritta con l'aggiunta di un parametro arguments, i riferimenti a arguments nel corpo della funzione sono relativi al parametro anziché all'oggetto arguments. Il codice seguente non produce alcun output:

    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

    Nelle versioni precedenti di ActionScript, l'oggetto arguments conteneva anche una proprietà denominata caller, che era un riferimento alla funzione che chiamava la funzione corrente. La proprietà caller non è presente in ActionScript 3.0, ma se occorre fare riferimento alla funzione chiamante, potete modificare quest'ultima in modo che passi un parametro supplementare contenente un riferimento a se stessa.

Il parametro ... (rest)

In ActionScript 3.0 è stata introdotta una nuova dichiarazione di parametro, il parametro ... (rest), che consente di specificare un parametro array che accetta qualunque numero di argomenti separati da virgole. Il parametro può avere qualsiasi nome che non corrisponda a una parola riservata e deve essere l'ultimo parametro specificato. L'uso di questo parametro rende indisponibile l'oggetto arguments. Anche se il parametro ... (rest) offre la stessa funzionalità dell'array arguments e della proprietà arguments.length, non fornisce invece una funzionalità simile a quella di arguments.callee. Prima di usare il parametro ... (rest), assicuratevi che non sia necessario utilizzare arguments.callee.

Il seguente esempio riscrive la funzione traceArgArray() utilizzando il parametro ... (rest) invece dell'oggetto arguments:

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

Il parametro ... (rest) può anche essere utilizzato con altri parametri, a condizione che venga specificato per ultimo. L'esempio seguente modifica la funzione traceArgArray() in modo tale che il primo parametro, x, sia del tipo int, e il secondo utilizzi il parametro ... (rest). L'output ignora il primo valore perché il primo parametro non fa più parte dell'array creato dal parametro ... (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

Funzioni come oggetti

In ActionScript 3.0, le funzioni sono oggetti. Quando create una funzione, ciò che viene creato è in realtà un oggetto che non solo può essere passato come parametro a un'altra funzione, ma che può disporre anche di proprietà e metodi.

Le funzioni specificate come argomenti per altre funzioni vengono passate mediante riferimento e non mediante un valore. Quando passate una funzione come argomento, utilizzate solo l'identificatore e omettete l'operatore parentesi usato per chiamare il metodo. Ad esempio, il codice seguente passa una funzione denominata clickListener() come argomento al metodo addEventListener():

addEventListener(MouseEvent.CLICK, clickListener);

Per quanto possa sembrare strano ai programmatori che iniziano a utilizzare ActionScript, le funzioni possono avere proprietà e metodi come qualunque altro oggetto. In effetti, ogni funzione dispone di una proprietà di sola lettura denominata length che memorizza il numero di parametri definiti per la funzione. Questa proprietà è diversa dalla proprietà arguments.length, che indica il numero di argomenti passati alla funzione. È bene ricordare che in ActionScript il numero di argomenti inviati a una funzione può superare quello dei parametri definiti per la stessa funzione. L'esempio seguente, che viene compilato solo in modalità standard perché la modalità rigorosa richiede una corrispondenza esatta tra il numero di argomenti passati e il numero di parametri definiti, mostra la differenza tra le due proprietà:

// 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 */

In modalità rigorosa, potete definire proprietà personalizzate per la funzione all'esterno del corpo della funzione. Le proprietà di funzione possono servire come proprietà “quasi statiche” che consentono di salvare lo stato di una variabile relativo alla funzione. Ad esempio, potrebbe essere utile registrare quante volte viene utilizzata una particolare funzione. Questa funzionalità può servire se si sta creando un videogame e si desidera registrare quante volte un utente utilizza un comando specifico (benché sia anche possibile utilizzare una proprietà di classe statica per lo stesso scopo). Nell'esempio seguente, che viene compilato solo in modalità standard poiché la modalità rigorosa non consente di aggiungere proprietà dinamiche alle funzioni, viene creata una proprietà di funzione all'esterno della dichiarazione di funzione e incrementata la proprietà ogni volta che la funzione viene chiamata:

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

Area di validità delle funzioni

L'area di validità di una funzione determina non solo l'area in cui, all'interno di un programma, quella funzione può essere chiamata, ma anche le definizioni alle quali la funzione può accedere. Le stesse regole dell'area di validità che valgono per gli identificatori delle variabili si applicano anche agli identificatori di funzione. Una funzione dichiarata nell'area di validità globale è disponibile in tutto il codice. Ad esempio, ActionScript 3.0 contiene funzioni globali, quali isNaN() e parseInt(), che sono disponibili in qualunque punto del codice. Una funzione nidificata (cioè dichiarata all'interno di un'altra funzione) può essere utilizzata in qualunque posizione all'interno della funzione in cui è stata dichiarata.

La catena dell'area di validità

Ogni volta che inizia l'esecuzione di una funzione, viene creata una serie di oggetti e di proprietà. Innanzi tutto, viene creato un oggetto speciale chiamato oggetto di attivazione, nel quale vengono memorizzati i parametri e le eventuali variabili locali o funzioni dichiarate nel corpo della funzione. Non è possibile accedere direttamente all'oggetto di attivazione perché è un meccanismo interno. In secondo luogo viene creata una catena dell'area di validità che contiene un elenco ordinato degli oggetti nei quali il runtime cerca le dichiarazioni di identificazione (gli identificatori). Ogni funzione che viene eseguita ha una catena dell'area di validità che viene memorizzata in una proprietà interna. Nel caso di una funzione nidificata, la catena dell'area di validità inizia con il proprio oggetto di attivazione, seguito dall'oggetto di attivazione della relativa funzione principale. La catena prosegue nello stesso modo fino al raggiungimento dell'oggetto globale, ovvero l'oggetto che viene creato all'inizio di un programma ActionScript e che contiene tutte le variabili globali e le funzioni.

Chiusure di funzione

Una chiusura di funzione è un oggetto che contiene un'istantanea della funzione e il relativo ambiente lessicale, il quale comprende tutte le variabili, le proprietà, i metodi e gli oggetti inclusi nella catena dell'area di validità della funzione, con i rispettivi valori. Le chiusure di funzione vengono create ogni volta che una funzione viene eseguita indipendentemente da un oggetto o da una classe. Il fatto che una chiusura di funzione mantenga l'area di validità nella quale è stata definita produce risultati interessanti quando una funzione viene passata in un'area di validità diversa come argomento o come valore restituito.

Il seguente codice, ad esempio, crea due funzioni: foo(), che restituisce una funzione nidificata di nome rectArea() che calcola l'area di un rettangolo, e bar(), che chiama foo() e memorizza la chiusura di funzione restituita in una variabile denominata myProduct. Anche se la funzione bar() definisce la propria variabile locale x (con valore 2), quando la chiusura di funzione myProduct() viene chiamata, essa mantiene la variabile x (con valore 40) definita nella funzione foo(). La funzione bar(), pertanto, restituisce il valore 160 anziché 8.

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

I metodi si comportano in modo analogo, perché conservano a loro volta le informazioni relative all'ambiente lessicale nel quale sono stati creati. Questa caratteristica è evidente soprattutto quando un metodo viene estratto dalla propria istanza per creare un metodo vincolato. La differenza principale tra una chiusura di funzione e un metodo vincolato consiste nel fatto che il valore della parola chiave this in un metodo vincolato fa sempre riferimento all'istanza alla quale è stata originariamente associata, mentre in una chiusura di funzione il valore di this può cambiare.